buildings = existing == null
? new ArrayList<>()
: new ArrayList<>(existing.buildings());
buildings.add(housing);
- BannerModSettlementSnapshot snapshot = existing == null
- ? new BannerModSettlementSnapshot(
+ SettlementSnapshot snapshot = existing == null
+ ? new SettlementSnapshot(
claim.getUUID(),
claim.getCenter().x,
claim.getCenter().z,
@@ -166,15 +166,15 @@ public static BannerModSettlementSnapshot seedHousingSnapshot(ServerLevel level,
level.getGameTime(),
Math.max(1, residentCapacity),
0, 0, 0, 0, 0,
- com.talhanation.bannermod.settlement.BannerModSettlementStockpileSummary.empty(),
- com.talhanation.bannermod.settlement.BannerModSettlementMarketState.empty(),
- com.talhanation.bannermod.settlement.BannerModSettlementDesiredGoodsSeed.empty(),
- com.talhanation.bannermod.settlement.BannerModSettlementProjectCandidateSeed.empty(),
- com.talhanation.bannermod.settlement.BannerModSettlementTradeRouteHandoffSeed.empty(),
- com.talhanation.bannermod.settlement.BannerModSettlementSupplySignalState.empty(),
+ com.talhanation.bannermod.settlement.SettlementStockpileSummary.empty(),
+ com.talhanation.bannermod.settlement.SettlementMarketState.empty(),
+ com.talhanation.bannermod.settlement.SettlementDesiredGoodsSnapshot.empty(),
+ com.talhanation.bannermod.settlement.SettlementProjectCandidateSnapshot.empty(),
+ com.talhanation.bannermod.settlement.SettlementTradeRouteHandoffSnapshot.empty(),
+ com.talhanation.bannermod.settlement.SettlementSupplySignalState.empty(),
List.of(),
buildings)
- : new BannerModSettlementSnapshot(
+ : new SettlementSnapshot(
existing.claimUuid(),
existing.anchorChunkX(),
existing.anchorChunkZ(),
@@ -188,9 +188,9 @@ public static BannerModSettlementSnapshot seedHousingSnapshot(ServerLevel level,
existing.missingWorkAreaAssignmentCount(),
existing.stockpileSummary(),
existing.marketState(),
- existing.desiredGoodsSeed(),
- existing.projectCandidateSeed(),
- existing.tradeRouteHandoffSeed(),
+ existing.desiredGoodsSnapshot(),
+ existing.projectCandidateSnapshot(),
+ existing.tradeRouteHandoffSnapshot(),
existing.supplySignalState(),
existing.residents(),
buildings);
diff --git a/src/gametest/java/com/talhanation/bannermod/BannerModHomeAssignGameTests.java b/src/gametest/java/com/talhanation/bannermod/BannerModHomeAssignGameTests.java
index 35d64bd7..cf3b6d2f 100644
--- a/src/gametest/java/com/talhanation/bannermod/BannerModHomeAssignGameTests.java
+++ b/src/gametest/java/com/talhanation/bannermod/BannerModHomeAssignGameTests.java
@@ -5,6 +5,12 @@
import com.talhanation.bannermod.entity.civilian.FarmerEntity;
import com.talhanation.bannermod.entity.military.RecruitEntity;
import com.talhanation.bannermod.network.messages.civilian.MessageAssignHome;
+import com.talhanation.bannermod.settlement.building.BuildingType;
+import com.talhanation.bannermod.settlement.building.BuildingValidationState;
+import com.talhanation.bannermod.settlement.building.ValidatedBuildingRecord;
+import com.talhanation.bannermod.settlement.building.ValidatedBuildingRegistryData;
+import com.talhanation.bannermod.settlement.building.ZoneRole;
+import com.talhanation.bannermod.settlement.building.ZoneSelection;
import net.minecraft.core.BlockPos;
import net.minecraft.gametest.framework.GameTest;
import net.minecraft.gametest.framework.GameTestHelper;
@@ -12,11 +18,14 @@
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.GameType;
+import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.phys.AABB;
import net.neoforged.neoforge.gametest.GameTestHolder;
import net.neoforged.neoforge.gametest.PrefixGameTestTemplate;
+import java.util.List;
import java.util.Optional;
import java.util.UUID;
@@ -27,7 +36,8 @@
* Recruits, workers, and citizens all expose a {@code homePos} that
* round-trips through NBT.
* {@link MessageAssignHome#handle} validates ownership and bed
- * targets (rejects unknown entity, non-owner, and non-bed pos).
+ * targets, then applies the same server-side home update used by the
+ * 30-second Assign Home selector flow.
*
*
* Save/load round-trip is exercised in the harness by the
@@ -125,7 +135,7 @@ public static void citizenHomePosRoundTripsThroughSaveLoad(GameTestHelper helper
@PrefixGameTestTemplate(false)
@GameTest(template = "harness_empty")
- public static void assignHomeAcceptsBedFromOwner(GameTestHelper helper) {
+ public static void assignHomeMessageAcceptsBedFromOwner(GameTestHelper helper) {
UUID ownerId = UUID.randomUUID();
ServerPlayer owner = (ServerPlayer) BannerModDedicatedServerGameTestSupport.createPositionedFakeServerPlayer(
helper.getLevel(), ownerId, "homeassign-owner", helper.absolutePos(BlockPos.ZERO));
@@ -134,6 +144,7 @@ public static void assignHomeAcceptsBedFromOwner(GameTestHelper helper) {
// Pin the recruit's owner explicitly to the fake server player so the
// ownership check inside MessageAssignHome#handle accepts the request.
recruit.setOwnerUUID(Optional.of(ownerId));
+ recruit.setHomeBuildAreaUUID(UUID.randomUUID());
BlockPos bedRel = new BlockPos(1, 1, 1);
BlockPos bedAbs = helper.absolutePos(bedRel);
@@ -143,7 +154,49 @@ public static void assignHomeAcceptsBedFromOwner(GameTestHelper helper) {
boolean accepted = MessageAssignHome.handle(owner, recruit.getUUID(), bedAbs);
helper.assertTrue(accepted, "Owner should be allowed to assign a bed as home");
helper.assertTrue(bedAbs.equals(recruit.getHomePos()),
- "Recruit homePos must update to the bed BlockPos after assign-home");
+ "Recruit homePos must update to the bed BlockPos through MessageAssignHome");
+ helper.assertTrue(recruit.getHomeBuildAreaUUID() == null,
+ "MessageAssignHome must clear stale prefab home linkage for direct bed assignment");
+
+ helper.succeed();
+ }
+
+ @PrefixGameTestTemplate(false)
+ @GameTest(template = "harness_empty")
+ public static void assignHomeMessageAcceptsValidatedSleepingZoneFromOwner(GameTestHelper helper) {
+ UUID ownerId = UUID.randomUUID();
+ ServerPlayer owner = (ServerPlayer) BannerModDedicatedServerGameTestSupport.createPositionedFakeServerPlayer(
+ helper.getLevel(), ownerId, "homeassign-zone-owner", helper.absolutePos(BlockPos.ZERO));
+
+ RecruitEntity recruit = BannerModGameTestSupport.spawnOwnedRecruit(helper, owner, BlockPos.ZERO);
+ recruit.setOwnerUUID(Optional.of(ownerId));
+ recruit.setHomeBuildAreaUUID(UUID.randomUUID());
+
+ BlockPos sleepMin = helper.absolutePos(new BlockPos(2, 1, 2));
+ BlockPos sleepMax = helper.absolutePos(new BlockPos(3, 1, 3));
+ BlockPos target = helper.absolutePos(new BlockPos(2, 1, 2));
+ ValidatedBuildingRegistryData.get(helper.getLevel()).registerBuilding(new ValidatedBuildingRecord(
+ UUID.randomUUID(),
+ UUID.randomUUID(),
+ BuildingType.HOUSE,
+ Level.OVERWORLD,
+ target,
+ List.of(new ZoneSelection(ZoneRole.SLEEPING, sleepMin, sleepMax, null)),
+ new AABB(sleepMin.getX(), sleepMin.getY(), sleepMin.getZ(), sleepMax.getX() + 1.0D, sleepMax.getY() + 1.0D, sleepMax.getZ() + 1.0D),
+ BuildingValidationState.VALID,
+ 1,
+ 80,
+ helper.getLevel().getGameTime(),
+ helper.getLevel().getGameTime(),
+ 0L
+ ));
+
+ boolean accepted = MessageAssignHome.handle(owner, recruit.getUUID(), target);
+ helper.assertTrue(accepted, "Owner should be allowed to assign a validated sleeping zone as home");
+ helper.assertTrue(target.equals(recruit.getHomePos()),
+ "Recruit homePos must update to the sleeping-zone BlockPos through MessageAssignHome");
+ helper.assertTrue(recruit.getHomeBuildAreaUUID() == null,
+ "MessageAssignHome must clear stale prefab home linkage for direct sleeping-zone assignment");
helper.succeed();
}
@@ -169,4 +222,28 @@ public static void assignHomeRejectsNonBedBlock(GameTestHelper helper) {
helper.succeed();
}
+
+ @PrefixGameTestTemplate(false)
+ @GameTest(template = "harness_empty")
+ public static void assignHomeRejectsForeignSender(GameTestHelper helper) {
+ UUID ownerId = UUID.randomUUID();
+ UUID intruderId = UUID.randomUUID();
+ ServerPlayer owner = (ServerPlayer) BannerModDedicatedServerGameTestSupport.createPositionedFakeServerPlayer(
+ helper.getLevel(), ownerId, "homeassign-owner-3", helper.absolutePos(BlockPos.ZERO));
+ ServerPlayer intruder = (ServerPlayer) BannerModDedicatedServerGameTestSupport.createPositionedFakeServerPlayer(
+ helper.getLevel(), intruderId, "homeassign-intruder", helper.absolutePos(BlockPos.ZERO));
+
+ RecruitEntity recruit = BannerModGameTestSupport.spawnOwnedRecruit(helper, owner, BlockPos.ZERO);
+ recruit.setOwnerUUID(Optional.of(ownerId));
+
+ BlockPos bedAbs = helper.absolutePos(new BlockPos(1, 1, 2));
+ helper.getLevel().setBlock(bedAbs, Blocks.RED_BED.defaultBlockState(), 3);
+
+ boolean accepted = MessageAssignHome.handle(intruder, recruit.getUUID(), bedAbs);
+ helper.assertFalse(accepted, "Foreign sender must not assign another player's recruit home");
+ helper.assertTrue(recruit.getHomePos() == null,
+ "Recruit homePos must remain unset after a rejected foreign assignment");
+
+ helper.succeed();
+ }
}
diff --git a/src/gametest/java/com/talhanation/bannermod/BannerModOwnershipCycleGameTests.java b/src/gametest/java/com/talhanation/bannermod/BannerModOwnershipCycleGameTests.java
index 5a4be10a..bda62e15 100644
--- a/src/gametest/java/com/talhanation/bannermod/BannerModOwnershipCycleGameTests.java
+++ b/src/gametest/java/com/talhanation/bannermod/BannerModOwnershipCycleGameTests.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod;
import com.talhanation.bannermod.bootstrap.BannerModMain;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.gametest.support.RecruitsBattleGameTestSupport;
import com.talhanation.bannermod.entity.civilian.FarmerEntity;
diff --git a/src/gametest/java/com/talhanation/bannermod/BannerModPathfindHomeGoalGameTests.java b/src/gametest/java/com/talhanation/bannermod/BannerModPathfindHomeGoalGameTests.java
index 2e80713a..bf0a30c1 100644
--- a/src/gametest/java/com/talhanation/bannermod/BannerModPathfindHomeGoalGameTests.java
+++ b/src/gametest/java/com/talhanation/bannermod/BannerModPathfindHomeGoalGameTests.java
@@ -9,6 +9,7 @@
import net.minecraft.gametest.framework.GameTest;
import net.minecraft.gametest.framework.GameTestHelper;
import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.block.Blocks;
@@ -27,10 +28,8 @@
* pathfinds the entity to within 3 blocks of that position; on arrival it
* either enters the bed at homePos or stops navigation as a sleep-on-ground
* fallback. These tests construct the goal directly against freshly spawned
- * recruits, workers, and citizens and exercise canUse/tick semantics rather
- * than waiting many simulated ticks for navigation to physically converge —
- * the navigation behaviour itself is exercised by other GameTests already
- * (BannerModTrueAsyncPathfindingGameTests).
+ * recruits, workers, and citizens so they exercise the home goal without
+ * unrelated selector priority or combat/work goals masking the assertion.
*/
@GameTestHolder(BannerModMain.MOD_ID)
public class BannerModPathfindHomeGoalGameTests {
@@ -41,15 +40,17 @@ public class BannerModPathfindHomeGoalGameTests {
private static long NIGHT = 14_000L;
@PrefixGameTestTemplate(false)
- @GameTest(template = "harness_empty")
+ @GameTest(template = "harness_empty", timeoutTicks = 400)
public static void recruitGoesHomeAtNight(GameTestHelper helper) {
Player owner = helper.makeMockPlayer(GameType.SURVIVAL);
- RecruitEntity recruit = BannerModGameTestSupport.spawnOwnedRecruit(helper, owner, BlockPos.ZERO);
+ prepareFlatPath(helper, new BlockPos(1, 0, 1), new BlockPos(12, 0, 1));
+
+ RecruitEntity recruit = BannerModGameTestSupport.spawnOwnedRecruit(helper, owner, new BlockPos(1, 1, 1));
// FollowState 0 = idle/free; otherwise the recruit's existing rest predicates
// suppress non-combat goals and our test would assert nothing meaningful.
recruit.setFollowState(0);
- BlockPos bedRel = new BlockPos(2, 1, 2);
+ BlockPos bedRel = new BlockPos(11, 1, 1);
BlockPos bedAbs = placeBed(helper, bedRel);
recruit.setHomePos(bedAbs);
@@ -66,6 +67,7 @@ public static void recruitGoesHomeAtNight(GameTestHelper helper) {
helper.assertTrue(goal.canUse(),
"PathfindHomeGoal must trigger for recruit at night with home assigned");
+ goal.start();
// Daytime regression: full health, full morale, day-time => goal must NOT trigger.
// Use a fresh goal instance because canUse() internally throttles at 20 ticks
@@ -83,17 +85,23 @@ public static void recruitGoesHomeAtNight(GameTestHelper helper) {
helper.assertFalse(dayGoal.canUse(),
"PathfindHomeGoal must stay dormant in daylight for a healthy recruit with home assigned");
- helper.succeed();
+ forceTimeOfDay(level, NIGHT);
+ helper.succeedWhen(() -> {
+ goal.tick();
+ assertWithinHomeRange(helper, recruit, bedAbs, "recruit");
+ });
}
@PrefixGameTestTemplate(false)
- @GameTest(template = "harness_empty")
+ @GameTest(template = "harness_empty", timeoutTicks = 400)
public static void workerGoesHomeAtNight(GameTestHelper helper) {
Player owner = helper.makeMockPlayer(GameType.SURVIVAL);
- FarmerEntity worker = BannerModGameTestSupport.spawnOwnedFarmer(helper, owner, BlockPos.ZERO);
+ prepareFlatPath(helper, new BlockPos(1, 0, 2), new BlockPos(12, 0, 2));
+
+ FarmerEntity worker = BannerModGameTestSupport.spawnOwnedFarmer(helper, owner, new BlockPos(1, 1, 2));
worker.setFollowState(0);
- BlockPos bedRel = new BlockPos(3, 1, 3);
+ BlockPos bedRel = new BlockPos(11, 1, 2);
BlockPos bedAbs = placeBed(helper, bedRel);
worker.setHomePos(bedAbs);
@@ -110,19 +118,25 @@ public static void workerGoesHomeAtNight(GameTestHelper helper) {
helper.assertTrue(goal.canUse(),
"PathfindHomeGoal must trigger for worker at night with home assigned");
+ goal.start();
- helper.succeed();
+ helper.succeedWhen(() -> {
+ goal.tick();
+ assertWithinHomeRange(helper, worker, bedAbs, "worker");
+ });
}
@PrefixGameTestTemplate(false)
- @GameTest(template = "harness_empty")
+ @GameTest(template = "harness_empty", timeoutTicks = 400)
public static void citizenGoesHomeAtNight(GameTestHelper helper) {
+ prepareFlatPath(helper, new BlockPos(1, 0, 3), new BlockPos(12, 0, 3));
+
CitizenEntity citizen = BannerModGameTestSupport.spawnEntity(
helper,
com.talhanation.bannermod.registry.citizen.ModCitizenEntityTypes.CITIZEN.get(),
- BlockPos.ZERO);
+ new BlockPos(1, 1, 3));
- BlockPos bedRel = new BlockPos(4, 1, 4);
+ BlockPos bedRel = new BlockPos(11, 1, 3);
BlockPos bedAbs = placeBed(helper, bedRel);
citizen.setHomePos(bedAbs);
@@ -132,6 +146,7 @@ public static void citizenGoesHomeAtNight(GameTestHelper helper) {
PathfindHomeGoal goal = new PathfindHomeGoal(citizen, citizen::getHomePos);
helper.assertTrue(goal.canUse(),
"PathfindHomeGoal must trigger for citizen at night with home assigned");
+ goal.start();
// Daytime regression for citizen: no stamina signal, so goal must be silent.
// Use a fresh goal instance — see recruitGoesHomeAtNight for the throttle rationale.
@@ -140,7 +155,11 @@ public static void citizenGoesHomeAtNight(GameTestHelper helper) {
helper.assertFalse(dayGoal.canUse(),
"PathfindHomeGoal must stay dormant in daylight for a citizen with home assigned");
- helper.succeed();
+ forceTimeOfDay(level, NIGHT);
+ helper.succeedWhen(() -> {
+ goal.tick();
+ assertWithinHomeRange(helper, citizen, bedAbs, "citizen");
+ });
}
@PrefixGameTestTemplate(false)
@@ -197,13 +216,15 @@ public static void arrivalAtBedTriggersSleep(GameTestHelper helper) {
* code path the level loader uses on world reload.
*/
@PrefixGameTestTemplate(false)
- @GameTest(template = "harness_empty")
+ @GameTest(template = "harness_empty", timeoutTicks = 400)
public static void rebuiltGoalResumesAfterReload(GameTestHelper helper) {
Player owner = helper.makeMockPlayer(GameType.SURVIVAL);
- RecruitEntity recruit = BannerModGameTestSupport.spawnOwnedRecruit(helper, owner, BlockPos.ZERO);
+ prepareFlatPath(helper, new BlockPos(1, 0, 4), new BlockPos(12, 0, 4));
+
+ RecruitEntity recruit = BannerModGameTestSupport.spawnOwnedRecruit(helper, owner, new BlockPos(1, 1, 4));
recruit.setFollowState(0);
- BlockPos bedRel = new BlockPos(2, 1, 2);
+ BlockPos bedRel = new BlockPos(11, 1, 4);
BlockPos bedAbs = placeBed(helper, bedRel);
recruit.setHomePos(bedAbs);
@@ -217,18 +238,51 @@ public static void rebuiltGoalResumesAfterReload(GameTestHelper helper) {
PathfindHomeGoal first = new PathfindHomeGoal(recruit, recruit::getHomePos, staminaSignal, 1.0D);
helper.assertTrue(first.canUse(), "Pre-reload goal must trigger");
first.start();
-
- // Simulate a reload: drop the goal instance, advance the clock past the
- // 20-tick canUse throttle, and rebuild against the same entity. The
- // entity's homePos survives because it lives on the entity's persistent
- // synched data (HOMEASSIGN-002), so the new goal must accept canUse with
- // no extra wiring.
+ first.tick();
+ // Clear the pre-reload route so arrival proves the rebuilt goal moved the recruit.
+ recruit.getNavigation().stop();
+
+ // Simulate a reload: drop the goal instance and rebuild against the same
+ // entity. The entity's homePos survives because it lives on the entity's
+ // persistent synched data (HOMEASSIGN-002), so the new goal must accept
+ // canUse with no extra wiring.
forceTimeOfDay(level, NIGHT + 100L);
PathfindHomeGoal rebuilt = new PathfindHomeGoal(recruit, recruit::getHomePos, staminaSignal, 1.0D);
helper.assertTrue(rebuilt.canUse(),
"Rebuilt goal must resume after reload because homePos is persistent");
+ rebuilt.start();
- helper.succeed();
+ helper.succeedWhen(() -> {
+ rebuilt.tick();
+ assertWithinHomeRange(helper, recruit, bedAbs, "restarted recruit");
+ });
+ }
+
+ private static void assertWithinHomeRange(GameTestHelper helper,
+ PathfinderMob mob,
+ BlockPos home,
+ String label) {
+ double distSqr = mob.position().distanceToSqr(
+ home.getX() + 0.5D, home.getY() + 0.5D, home.getZ() + 0.5D);
+ helper.assertTrue(distSqr <= 9.0D,
+ "Expected " + label + " to reach within 3 blocks of assigned home; distance squared was " + distSqr);
+ }
+
+ private static void prepareFlatPath(GameTestHelper helper, BlockPos fromRel, BlockPos toRel) {
+ int minX = Math.min(fromRel.getX(), toRel.getX());
+ int maxX = Math.max(fromRel.getX(), toRel.getX());
+ int minZ = Math.min(fromRel.getZ(), toRel.getZ());
+ int maxZ = Math.max(fromRel.getZ(), toRel.getZ());
+ for (int x = minX; x <= maxX; x++) {
+ for (int z = minZ; z <= maxZ; z++) {
+ helper.getLevel().setBlockAndUpdate(helper.absolutePos(new BlockPos(x, fromRel.getY(), z)),
+ Blocks.STONE.defaultBlockState());
+ helper.getLevel().setBlockAndUpdate(helper.absolutePos(new BlockPos(x, fromRel.getY() + 1, z)),
+ Blocks.AIR.defaultBlockState());
+ helper.getLevel().setBlockAndUpdate(helper.absolutePos(new BlockPos(x, fromRel.getY() + 2, z)),
+ Blocks.AIR.defaultBlockState());
+ }
+ }
}
/**
diff --git a/src/gametest/java/com/talhanation/bannermod/BannerModPlayerCycleGameTests.java b/src/gametest/java/com/talhanation/bannermod/BannerModPlayerCycleGameTests.java
index 3ff60469..422780da 100644
--- a/src/gametest/java/com/talhanation/bannermod/BannerModPlayerCycleGameTests.java
+++ b/src/gametest/java/com/talhanation/bannermod/BannerModPlayerCycleGameTests.java
@@ -2,7 +2,7 @@
import com.talhanation.bannermod.shared.logistics.BannerModSupplyStatus;
import com.talhanation.bannermod.bootstrap.BannerModMain;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.gametest.support.RecruitsBattleGameTestSupport;
import com.talhanation.bannermod.entity.civilian.FarmerEntity;
diff --git a/src/gametest/java/com/talhanation/bannermod/BannerModSettlementFactionEnforcementGameTests.java b/src/gametest/java/com/talhanation/bannermod/BannerModSettlementFactionEnforcementGameTests.java
index 4c239eec..8580432a 100644
--- a/src/gametest/java/com/talhanation/bannermod/BannerModSettlementFactionEnforcementGameTests.java
+++ b/src/gametest/java/com/talhanation/bannermod/BannerModSettlementFactionEnforcementGameTests.java
@@ -207,12 +207,11 @@ private static boolean isInsideOwnFactionClaim(ServerPlayer player, BlockPos tar
if (player.getTeam() == null || ClaimEvents.claimManager() == null) {
return false;
}
- ChunkPos chunkPos = new ChunkPos(targetPos);
- RecruitsClaim claim = ClaimEvents.claimManager().getClaim(chunkPos);
- return claim != null
- && claim.containsChunk(chunkPos)
- && claim.getOwnerPoliticalEntityId() != null
- && claim.getOwnerPoliticalEntityId().equals(com.talhanation.bannermod.war.registry.PoliticalMembership.entityIdFor(
- com.talhanation.bannermod.war.WarRuntimeContext.registry(player.serverLevel()), player.getUUID()));
+ BannerModSettlementBinding.Binding binding = BannerModSettlementBinding.resolveFactionStatus(
+ ClaimEvents.claimManager(),
+ targetPos,
+ player.getTeam().getName()
+ );
+ return binding.isFriendly();
}
}
diff --git a/src/gametest/java/com/talhanation/bannermod/BannerModSettlementProjectGameTests.java b/src/gametest/java/com/talhanation/bannermod/BannerModSettlementProjectGameTests.java
index 83a0da01..92639f5d 100644
--- a/src/gametest/java/com/talhanation/bannermod/BannerModSettlementProjectGameTests.java
+++ b/src/gametest/java/com/talhanation/bannermod/BannerModSettlementProjectGameTests.java
@@ -4,14 +4,14 @@
import com.talhanation.bannermod.entity.civilian.workarea.BuildArea;
import com.talhanation.bannermod.entity.civilian.workarea.WorkAreaIndex;
import com.talhanation.bannermod.persistence.military.RecruitsClaim;
-import com.talhanation.bannermod.settlement.BannerModSettlementBuildingCategory;
-import com.talhanation.bannermod.settlement.BannerModSettlementBuildingProfileSeed;
+import com.talhanation.bannermod.settlement.SettlementBuildingCategory;
+import com.talhanation.bannermod.settlement.SettlementBuildingProfileSeed;
import com.talhanation.bannermod.settlement.growth.PendingProject;
import com.talhanation.bannermod.settlement.growth.ProjectBlocker;
import com.talhanation.bannermod.settlement.growth.ProjectKind;
import com.talhanation.bannermod.settlement.project.AssignmentPhase;
import com.talhanation.bannermod.settlement.project.BannerModBuildAreaProjectBridge;
-import com.talhanation.bannermod.settlement.project.BannerModSettlementProjectRuntime;
+import com.talhanation.bannermod.settlement.project.SettlementProjectRuntime;
import com.talhanation.bannermod.settlement.project.ProjectAssignment;
import net.minecraft.core.BlockPos;
import net.minecraft.gametest.framework.GameTest;
@@ -65,16 +65,16 @@ private static void runAssertSettlementProjectCreatesExecutableBuildAreaInWorld(
UUID.randomUUID(),
ProjectKind.NEW_BUILDING,
null,
- BannerModSettlementBuildingCategory.GENERAL,
- BannerModSettlementBuildingProfileSeed.GENERAL,
+ SettlementBuildingCategory.GENERAL,
+ SettlementBuildingProfileSeed.GENERAL,
100,
level.getGameTime(),
20,
ProjectBlocker.NONE
);
- BannerModSettlementProjectRuntime runtime = BannerModSettlementProjectRuntime.forServer(level);
- ProjectAssignment assignment = BannerModSettlementProjectRuntime.tickClaim(
+ SettlementProjectRuntime runtime = SettlementProjectRuntime.forServer(level);
+ ProjectAssignment assignment = SettlementProjectRuntime.tickClaim(
level,
claim.getUUID(),
List.of(project)
@@ -118,15 +118,15 @@ static void assertSettlementProjectBindsToExecutableBuildAreaTarget(GameTestHelp
UUID.randomUUID(),
ProjectKind.NEW_BUILDING,
null,
- BannerModSettlementBuildingCategory.GENERAL,
- BannerModSettlementBuildingProfileSeed.GENERAL,
+ SettlementBuildingCategory.GENERAL,
+ SettlementBuildingProfileSeed.GENERAL,
100,
level.getGameTime(),
20,
ProjectBlocker.NONE
);
- Optional assignment = BannerModSettlementProjectRuntime.detachedForTests().tickClaim(
+ Optional assignment = SettlementProjectRuntime.detachedForTests().tickClaim(
level,
claim.getUUID(),
List.of(project),
@@ -161,15 +161,15 @@ static void assertSettlementProjectProgressesFromBuildExecutionEvents(GameTestHe
UUID.randomUUID(),
ProjectKind.NEW_BUILDING,
null,
- BannerModSettlementBuildingCategory.GENERAL,
- BannerModSettlementBuildingProfileSeed.GENERAL,
+ SettlementBuildingCategory.GENERAL,
+ SettlementBuildingProfileSeed.GENERAL,
100,
level.getGameTime(),
20,
ProjectBlocker.NONE
);
- BannerModSettlementProjectRuntime runtime = BannerModSettlementProjectRuntime.forServer(level);
+ SettlementProjectRuntime runtime = SettlementProjectRuntime.forServer(level);
ProjectAssignment assignment = runtime.tickClaim(
level,
claim.getUUID(),
diff --git a/src/gametest/java/com/talhanation/bannermod/BannerModStarterFortGameTestSupport.java b/src/gametest/java/com/talhanation/bannermod/BannerModStarterFortGameTestSupport.java
index 4a61d8dc..39819fe9 100644
--- a/src/gametest/java/com/talhanation/bannermod/BannerModStarterFortGameTestSupport.java
+++ b/src/gametest/java/com/talhanation/bannermod/BannerModStarterFortGameTestSupport.java
@@ -6,7 +6,7 @@
import com.talhanation.bannermod.settlement.building.ZoneSelection;
import com.talhanation.bannermod.settlement.validation.BuildingValidationRequest;
import com.talhanation.bannermod.settlement.validation.BuildingValidationResult;
-import com.talhanation.bannermod.settlement.validation.DefaultBuildingValidator;
+import com.talhanation.bannermod.settlement.validation.SettlementBuildingValidator;
import com.talhanation.bannermod.settlement.validation.StarterFortPlan;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
@@ -47,7 +47,7 @@ public static void buildValidFort(ServerLevel level, BlockPos anchor) {
}
public static BuildingValidationResult validateStarterFort(ServerLevel level, BlockPos anchor) {
- return new DefaultBuildingValidator(new BuildingDefinitionRegistry()).validate(
+ return new SettlementBuildingValidator(new BuildingDefinitionRegistry()).validate(
level,
null,
new BuildingValidationRequest(
diff --git a/src/gametest/java/com/talhanation/bannermod/BannerModWorkOrderClaimReleaseGameTests.java b/src/gametest/java/com/talhanation/bannermod/BannerModWorkOrderClaimReleaseGameTests.java
index 3577e849..e6da08c7 100644
--- a/src/gametest/java/com/talhanation/bannermod/BannerModWorkOrderClaimReleaseGameTests.java
+++ b/src/gametest/java/com/talhanation/bannermod/BannerModWorkOrderClaimReleaseGameTests.java
@@ -3,7 +3,7 @@
import com.talhanation.bannermod.bootstrap.BannerModMain;
import com.talhanation.bannermod.entity.civilian.FarmerEntity;
import com.talhanation.bannermod.events.civilian.SettlementWorkOrderClaimReleaseEvents;
-import com.talhanation.bannermod.settlement.BannerModSettlementOrchestrator;
+import com.talhanation.bannermod.settlement.SettlementOrchestrator;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrder;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrderRuntime;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrderStatus;
@@ -57,7 +57,7 @@ public static void workerDeathReleasesActiveWorkOrderClaim(GameTestHelper helper
BannerModDedicatedServerGameTestSupport.assignDetachedOwnership(worker, LEADER_UUID);
BannerModDedicatedServerGameTestSupport.joinTeam(level, TEAM_ID, worker);
- SettlementWorkOrderRuntime runtime = BannerModSettlementOrchestrator.workOrderRuntime(level);
+ SettlementWorkOrderRuntime runtime = SettlementOrchestrator.workOrderRuntime(level);
helper.assertTrue(runtime != null, "Expected the level to expose a SettlementWorkOrderRuntime.");
SettlementWorkOrder published = runtime.publish(SettlementWorkOrder.pending(
DEATH_CLAIM_UUID, DEATH_BUILDING_UUID, SettlementWorkOrderType.HARVEST_CROP,
@@ -103,7 +103,7 @@ public static void workerForcedRemovalReleasesActiveWorkOrderClaim(GameTestHelpe
BannerModDedicatedServerGameTestSupport.assignDetachedOwnership(worker, LEADER_UUID);
BannerModDedicatedServerGameTestSupport.joinTeam(level, TEAM_ID, worker);
- SettlementWorkOrderRuntime runtime = BannerModSettlementOrchestrator.workOrderRuntime(level);
+ SettlementWorkOrderRuntime runtime = SettlementOrchestrator.workOrderRuntime(level);
helper.assertTrue(runtime != null, "Expected the level to expose a SettlementWorkOrderRuntime.");
SettlementWorkOrder published = runtime.publish(SettlementWorkOrder.pending(
DISCARD_CLAIM_UUID, DISCARD_BUILDING_UUID, SettlementWorkOrderType.HARVEST_CROP,
diff --git a/src/gametest/java/com/talhanation/bannermod/BannerModWorkOrderTransportGameTests.java b/src/gametest/java/com/talhanation/bannermod/BannerModWorkOrderTransportGameTests.java
index 61d30fde..c71e7e89 100644
--- a/src/gametest/java/com/talhanation/bannermod/BannerModWorkOrderTransportGameTests.java
+++ b/src/gametest/java/com/talhanation/bannermod/BannerModWorkOrderTransportGameTests.java
@@ -2,7 +2,7 @@
import com.talhanation.bannermod.ai.civilian.TransportContainerExchange;
import com.talhanation.bannermod.bootstrap.BannerModMain;
-import com.talhanation.bannermod.settlement.BannerModSettlementOrchestrator;
+import com.talhanation.bannermod.settlement.SettlementOrchestrator;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrder;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrderRuntime;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrderStatus;
@@ -70,7 +70,7 @@ public static void fetchInputOrderRoutesItemsFromSourceToDestinationChest(GameTe
"Expected vanilla chests at the configured FETCH_INPUT anchor positions.");
sourceChest.setItem(0, new ItemStack(Items.WHEAT, 8));
- SettlementWorkOrderRuntime runtime = BannerModSettlementOrchestrator.workOrderRuntime(level);
+ SettlementWorkOrderRuntime runtime = SettlementOrchestrator.workOrderRuntime(level);
helper.assertTrue(runtime != null, "Expected the level to expose a SettlementWorkOrderRuntime.");
SettlementWorkOrder published = runtime.publish(SettlementWorkOrder.pendingTransport(
CLAIM_UUID,
@@ -132,7 +132,7 @@ public static void fetchInputResourceHintFilterIgnoresNonMatchingItemsInSharedCh
sourceChest.setItem(0, new ItemStack(Items.WHEAT, 8));
sourceChest.setItem(1, new ItemStack(Items.BREAD, 8));
- SettlementWorkOrderRuntime runtime = BannerModSettlementOrchestrator.workOrderRuntime(level);
+ SettlementWorkOrderRuntime runtime = SettlementOrchestrator.workOrderRuntime(level);
SettlementWorkOrder claimed = runtime.publish(SettlementWorkOrder.pendingTransport(
CLAIM_UUID, BUILDING_UUID, SettlementWorkOrderType.FETCH_INPUT,
sourceAbs, destinationAbs, "minecraft:wheat", 8, 70, level.getGameTime()
@@ -184,7 +184,7 @@ public static void multiStorageRoutingDrainsOnlyTheChestAtTheOrdersSourceAddress
decoyA.setItem(0, new ItemStack(Items.WHEAT, 64));
// decoyB stays empty — must not silently receive the deposit either.
- SettlementWorkOrderRuntime runtime = BannerModSettlementOrchestrator.workOrderRuntime(level);
+ SettlementWorkOrderRuntime runtime = SettlementOrchestrator.workOrderRuntime(level);
SettlementWorkOrder claimed = runtime.publish(SettlementWorkOrder.pendingTransport(
CLAIM_UUID, BUILDING_UUID, SettlementWorkOrderType.FETCH_INPUT,
sourceAbs, destinationAbs, "minecraft:wheat", 12, 70, level.getGameTime()
diff --git a/src/gametest/java/com/talhanation/bannermod/BannerModWorkerReassignAuthorityGameTests.java b/src/gametest/java/com/talhanation/bannermod/BannerModWorkerReassignAuthorityGameTests.java
new file mode 100644
index 00000000..0f54e796
--- /dev/null
+++ b/src/gametest/java/com/talhanation/bannermod/BannerModWorkerReassignAuthorityGameTests.java
@@ -0,0 +1,109 @@
+package com.talhanation.bannermod;
+
+import com.talhanation.bannermod.bootstrap.BannerModMain;
+import com.talhanation.bannermod.citizen.CitizenProfession;
+import com.talhanation.bannermod.entity.civilian.AbstractWorkerEntity;
+import com.talhanation.bannermod.entity.civilian.FarmerEntity;
+import com.talhanation.bannermod.entity.civilian.LumberjackEntity;
+import com.talhanation.bannermod.entity.civilian.WorkerCitizenConversionService;
+import net.minecraft.core.BlockPos;
+import net.minecraft.gametest.framework.GameTest;
+import net.minecraft.gametest.framework.GameTestHelper;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.phys.AABB;
+import net.neoforged.neoforge.gametest.GameTestHolder;
+import net.neoforged.neoforge.gametest.PrefixGameTestTemplate;
+
+import java.util.List;
+import java.util.UUID;
+
+@GameTestHolder(BannerModMain.MOD_ID)
+public class BannerModWorkerReassignAuthorityGameTests {
+ private static final UUID OWNER_UUID = UUID.fromString("00000000-0000-0000-0000-000000001a01");
+ private static final UUID OUTSIDER_UUID = UUID.fromString("00000000-0000-0000-0000-000000001a02");
+ private static final BlockPos WORKER_POS = new BlockPos(3, 2, 3);
+
+ @PrefixGameTestTemplate(false)
+ @GameTest(template = "harness_empty")
+ public static void nonOwnerReassignDeniedAndWorkerStateUnchanged(GameTestHelper helper) {
+ ServerLevel level = helper.getLevel();
+ BlockPos workerAbsolutePos = helper.absolutePos(WORKER_POS);
+ ServerPlayer owner = createPlayer(level, OWNER_UUID, "workerui-001a-owner", workerAbsolutePos);
+ ServerPlayer outsider = createPlayer(level, OUTSIDER_UUID, "workerui-001a-outsider", workerAbsolutePos);
+ FarmerEntity worker = BannerModGameTestSupport.spawnOwnedFarmer(helper, owner, WORKER_POS);
+
+ UUID workerUuid = worker.getUUID();
+ UUID ownerUuid = worker.getOwnerUUID();
+ int followState = worker.getFollowState();
+ BlockPos blockPos = worker.blockPosition();
+
+ String denialKey = WorkerCitizenConversionService.reassignProfession(
+ outsider,
+ worker,
+ CitizenProfession.LUMBERJACK
+ );
+
+ helper.assertTrue("gui.bannermod.worker_screen.convert.denied.not_controller".equals(denialKey),
+ "Expected non-owner worker reassignment to return the not-controller denial key");
+ helper.assertFalse(worker.isRemoved(),
+ "Expected denied reassignment to keep the original worker entity alive");
+ helper.assertTrue(level.getEntity(workerUuid) == worker,
+ "Expected denied reassignment to keep the same worker entity registered");
+ helper.assertTrue(worker instanceof FarmerEntity,
+ "Expected denied reassignment to keep the original farmer profession/entity type");
+ helper.assertTrue(ownerUuid != null && ownerUuid.equals(worker.getOwnerUUID()),
+ "Expected denied reassignment to preserve worker ownership");
+ helper.assertTrue(worker.isOwned(),
+ "Expected denied reassignment to preserve owned state");
+ helper.assertTrue(followState == worker.getFollowState(),
+ "Expected denied reassignment to preserve follow state");
+ helper.assertTrue(blockPos.equals(worker.blockPosition()),
+ "Expected denied reassignment to preserve worker position");
+ helper.assertTrue(workersNear(level, workerAbsolutePos).size() == 1,
+ "Expected denied reassignment not to spawn a replacement worker");
+ helper.succeed();
+ }
+
+ @PrefixGameTestTemplate(false)
+ @GameTest(template = "harness_empty")
+ public static void ownerReassignSmokeReplacesWorkerProfession(GameTestHelper helper) {
+ ServerLevel level = helper.getLevel();
+ BlockPos workerAbsolutePos = helper.absolutePos(WORKER_POS);
+ ServerPlayer owner = createPlayer(level, OWNER_UUID, "workerui-001a-owner-success", workerAbsolutePos);
+ FarmerEntity worker = BannerModGameTestSupport.spawnOwnedFarmer(helper, owner, WORKER_POS);
+ UUID oldWorkerUuid = worker.getUUID();
+
+ String denialKey = WorkerCitizenConversionService.reassignProfession(
+ owner,
+ worker,
+ CitizenProfession.LUMBERJACK
+ );
+
+ helper.assertTrue(denialKey == null,
+ "Expected owner worker reassignment to succeed");
+ helper.assertTrue(worker.isRemoved(),
+ "Expected successful reassignment to remove the original worker");
+ helper.assertTrue(level.getEntity(oldWorkerUuid) == null,
+ "Expected successful reassignment to unregister the original worker entity");
+ List workers = workersNear(level, workerAbsolutePos);
+ helper.assertTrue(workers.size() == 1,
+ "Expected successful reassignment to leave exactly one replacement worker");
+ AbstractWorkerEntity replacement = workers.get(0);
+ helper.assertTrue(replacement instanceof LumberjackEntity,
+ "Expected successful reassignment to spawn a lumberjack replacement");
+ helper.assertTrue(OWNER_UUID.equals(replacement.getOwnerUUID()),
+ "Expected successful reassignment to preserve owner UUID");
+ helper.assertTrue(replacement.isOwned(),
+ "Expected successful reassignment to preserve owned state");
+ helper.succeed();
+ }
+
+ private static ServerPlayer createPlayer(ServerLevel level, UUID playerId, String name, BlockPos pos) {
+ return (ServerPlayer) BannerModDedicatedServerGameTestSupport.createPositionedFakeServerPlayer(level, playerId, name, pos);
+ }
+
+ private static List workersNear(ServerLevel level, BlockPos pos) {
+ return level.getEntitiesOfClass(AbstractWorkerEntity.class, new AABB(pos).inflate(2.0D));
+ }
+}
diff --git a/src/gametest/java/com/talhanation/bannermod/entity/civilian/BannerModStarterWorkerReadinessGameTests.java b/src/gametest/java/com/talhanation/bannermod/entity/civilian/BannerModStarterWorkerReadinessGameTests.java
index e6416dc8..5e2a84c6 100644
--- a/src/gametest/java/com/talhanation/bannermod/entity/civilian/BannerModStarterWorkerReadinessGameTests.java
+++ b/src/gametest/java/com/talhanation/bannermod/entity/civilian/BannerModStarterWorkerReadinessGameTests.java
@@ -13,7 +13,7 @@
import com.talhanation.bannermod.settlement.bootstrap.SettlementBootstrapService;
import com.talhanation.bannermod.settlement.validation.BuildingValidationRequest;
import com.talhanation.bannermod.settlement.validation.BuildingValidationResult;
-import com.talhanation.bannermod.settlement.validation.DefaultBuildingValidator;
+import com.talhanation.bannermod.settlement.validation.SettlementBuildingValidator;
import net.minecraft.core.BlockPos;
import net.minecraft.gametest.framework.GameTest;
import net.minecraft.gametest.framework.GameTestHelper;
@@ -99,7 +99,11 @@ private static T singleWorker(GameTestHelper he
private static void assertIdleReason(GameTestHelper helper, AbstractWorkerEntity worker, String expectedReason) {
WorkerControlStatus status = worker.controlAccess().workStatus();
helper.assertTrue(status.kind() == WorkerControlStatus.Kind.IDLE,
- "Expected idle work status for " + worker.getName().getString() + ".");
+ "Expected idle work status for " + worker.getClass().getSimpleName() + " " + worker.getName().getString()
+ + ", got kind=" + status.kind() + ", reason=" + status.reasonToken()
+ + ", shouldWork=" + worker.shouldWork()
+ + ", needsSleep=" + worker.needsToSleep()
+ + ", currentWorkArea=" + worker.getCurrentWorkArea() + ".");
helper.assertTrue(expectedReason.equals(status.reasonToken()),
"Expected idle reason " + expectedReason + " for " + worker.getName().getString() + ", got " + status.reasonToken() + ".");
}
diff --git a/src/gametest/java/com/talhanation/bannermod/entity/military/perks/BannerModSkillTreePersistenceGameTests.java b/src/gametest/java/com/talhanation/bannermod/entity/military/perks/BannerModSkillTreePersistenceGameTests.java
new file mode 100644
index 00000000..7332df51
--- /dev/null
+++ b/src/gametest/java/com/talhanation/bannermod/entity/military/perks/BannerModSkillTreePersistenceGameTests.java
@@ -0,0 +1,116 @@
+package com.talhanation.bannermod.entity.military.perks;
+
+import com.mojang.authlib.GameProfile;
+import com.talhanation.bannermod.BannerModDedicatedServerGameTestSupport;
+import com.talhanation.bannermod.bootstrap.BannerModMain;
+import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
+import com.talhanation.bannermod.gametest.support.RecruitsBattleGameTestSupport;
+import com.talhanation.bannermod.registry.military.ModEntityTypes;
+import net.minecraft.core.BlockPos;
+import net.minecraft.gametest.framework.GameTest;
+import net.minecraft.gametest.framework.GameTestHelper;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.neoforged.neoforge.common.util.FakePlayer;
+import net.neoforged.neoforge.gametest.GameTestHolder;
+import net.neoforged.neoforge.gametest.PrefixGameTestTemplate;
+
+import java.util.UUID;
+
+@GameTestHolder(BannerModMain.MOD_ID)
+public class BannerModSkillTreePersistenceGameTests {
+ private static final UUID RECRUIT_OWNER_UUID = UUID.fromString("00000000-0000-0000-0000-000000002c01");
+ private static final UUID PLAYER_UUID = UUID.fromString("00000000-0000-0000-0000-000000002c02");
+ private static final String RECRUIT_PERK_ID = "universal/toughness_i";
+ private static final String PLAYER_PERK_ID = "swordsman/iron_grip_i";
+
+ @PrefixGameTestTemplate(false)
+ @GameTest(template = "harness_empty")
+ public static void recruitPerksAndSkillPointsSurviveSaveLoad(GameTestHelper helper) {
+ AbstractRecruitEntity recruit = RecruitsBattleGameTestSupport.spawnConfiguredRecruit(
+ helper,
+ ModEntityTypes.RECRUIT.get(),
+ new BlockPos(1, 2, 1),
+ "skilltree-recruit",
+ RECRUIT_OWNER_UUID
+ );
+ PerkNode node = PerkRegistry.get(RECRUIT_PERK_ID).orElseThrow();
+ recruit.getPerkProgress().grantPoints(3);
+ helper.assertTrue(recruit.getPerkProgress().unlock(node) == PerkProgress.UnlockResult.OK,
+ "Expected recruit test perk to unlock before save");
+
+ CompoundTag saved = BannerModDedicatedServerGameTestSupport.saveEntity(recruit);
+ recruit.discard();
+ AbstractRecruitEntity reloaded = BannerModDedicatedServerGameTestSupport.loadEntity(
+ helper,
+ ModEntityTypes.RECRUIT.get(),
+ new BlockPos(2, 2, 1),
+ saved
+ );
+
+ helper.assertTrue(reloaded.getPerkProgress().isOwned(RECRUIT_PERK_ID),
+ "Expected recruit unlocked perk to survive save/load");
+ helper.assertTrue(reloaded.getPerkProgress().getAvailablePoints() == 2,
+ "Expected recruit skill points to survive save/load");
+ helper.succeed();
+ }
+
+ @PrefixGameTestTemplate(false)
+ @GameTest(template = "harness_empty")
+ public static void playerAttachmentPerksAndSkillPointsSurviveSaveLoad(GameTestHelper helper) {
+ ServerLevel level = helper.getLevel();
+ ServerPlayer player = (ServerPlayer) BannerModDedicatedServerGameTestSupport.createPositionedFakeServerPlayer(
+ level,
+ PLAYER_UUID,
+ "skilltree-player",
+ helper.absolutePos(new BlockPos(1, 2, 2))
+ );
+ PlayerPerkProgressService.grantLevelPoints(player, 3);
+ helper.assertTrue(PlayerPerkProgressService.unlock(player, PLAYER_PERK_ID) == PerkProgress.UnlockResult.OK,
+ "Expected player test perk to unlock before save");
+
+ CompoundTag saved = BannerModDedicatedServerGameTestSupport.saveEntity(player);
+ ServerPlayer reloaded = new FakePlayer(level, new GameProfile(UUID.fromString("00000000-0000-0000-0000-000000002c03"), "skilltree-reloaded"));
+ reloaded.load(saved);
+
+ PerkProgress restored = PlayerPerkProgressService.progress(reloaded);
+ helper.assertTrue(restored.isOwned(PLAYER_PERK_ID),
+ "Expected player attachment unlocked perk to survive save/load");
+ helper.assertTrue(restored.getAvailablePoints() == 2,
+ "Expected player attachment skill points to survive save/load");
+ helper.succeed();
+ }
+
+ @PrefixGameTestTemplate(false)
+ @GameTest(template = "harness_empty")
+ public static void respecRefundsPointsWithoutChangingXpOrLevel(GameTestHelper helper) {
+ AbstractRecruitEntity recruit = RecruitsBattleGameTestSupport.spawnConfiguredRecruit(
+ helper,
+ ModEntityTypes.RECRUIT.get(),
+ new BlockPos(1, 2, 3),
+ "skilltree-respec-recruit",
+ RECRUIT_OWNER_UUID
+ );
+ recruit.setXpLevel(7);
+ recruit.setXp(42);
+ PerkNode node = PerkRegistry.get(RECRUIT_PERK_ID).orElseThrow();
+ recruit.getPerkProgress().grantPoints(2);
+ helper.assertTrue(recruit.getPerkProgress().unlock(node) == PerkProgress.UnlockResult.OK,
+ "Expected recruit test perk to unlock before respec");
+
+ int refund = recruit.getPerkProgress().respec();
+
+ helper.assertTrue(refund == node.pointCost(),
+ "Expected respec to refund the unlocked perk cost");
+ helper.assertTrue(recruit.getPerkProgress().getAvailablePoints() == 2,
+ "Expected respec to restore spent skill points");
+ helper.assertTrue(recruit.getPerkProgress().getOwnedPerks().isEmpty(),
+ "Expected respec to clear unlocked perks");
+ helper.assertTrue(recruit.getXpLevel() == 7,
+ "Expected respec to preserve recruit XP level");
+ helper.assertTrue(recruit.getXp() == 42,
+ "Expected respec to preserve recruit XP progress");
+ helper.succeed();
+ }
+}
diff --git a/src/gametest/java/com/talhanation/bannermod/gametest/support/RecruitsBattleGameTestSupport.java b/src/gametest/java/com/talhanation/bannermod/gametest/support/RecruitsBattleGameTestSupport.java
index a970f8a2..2ff5e353 100644
--- a/src/gametest/java/com/talhanation/bannermod/gametest/support/RecruitsBattleGameTestSupport.java
+++ b/src/gametest/java/com/talhanation/bannermod/gametest/support/RecruitsBattleGameTestSupport.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.gametest.support;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.entity.military.BowmanEntity;
import com.talhanation.bannermod.entity.military.CrossBowmanEntity;
diff --git a/src/gametest/java/com/talhanation/bannermod/network/messages/PacketAuthorityGameTests.java b/src/gametest/java/com/talhanation/bannermod/network/messages/PacketAuthorityGameTests.java
index 58598c0d..ebf57fdd 100644
--- a/src/gametest/java/com/talhanation/bannermod/network/messages/PacketAuthorityGameTests.java
+++ b/src/gametest/java/com/talhanation/bannermod/network/messages/PacketAuthorityGameTests.java
@@ -6,7 +6,7 @@
import com.talhanation.bannermod.bootstrap.BannerModMain;
import com.talhanation.bannermod.entity.civilian.workarea.StorageArea;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.gametest.support.PacketGameTestSupport;
import com.talhanation.bannermod.gametest.support.RecruitsBattleGameTestSupport;
import com.talhanation.bannermod.network.messages.civilian.MessageUpdateOwner;
diff --git a/src/gametest/java/com/talhanation/bannermod/network/messages/military/GroupAssignmentAuthorityGameTests.java b/src/gametest/java/com/talhanation/bannermod/network/messages/military/GroupAssignmentAuthorityGameTests.java
index 59601d38..75f44de2 100644
--- a/src/gametest/java/com/talhanation/bannermod/network/messages/military/GroupAssignmentAuthorityGameTests.java
+++ b/src/gametest/java/com/talhanation/bannermod/network/messages/military/GroupAssignmentAuthorityGameTests.java
@@ -3,7 +3,7 @@
import com.talhanation.bannermod.bootstrap.BannerModMain;
import com.talhanation.bannermod.entity.military.AbstractLeaderEntity;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.gametest.support.RecruitsBattleGameTestSupport;
import com.talhanation.bannermod.gametest.support.RecruitsCommandGameTestSupport;
import com.talhanation.bannermod.BannerModDedicatedServerGameTestSupport;
diff --git a/src/gametest/java/com/talhanation/bannermod/persistence/ChunkUnloadReloadRoundtripGameTests.java b/src/gametest/java/com/talhanation/bannermod/persistence/ChunkUnloadReloadRoundtripGameTests.java
index 9c054a03..2db6ab62 100644
--- a/src/gametest/java/com/talhanation/bannermod/persistence/ChunkUnloadReloadRoundtripGameTests.java
+++ b/src/gametest/java/com/talhanation/bannermod/persistence/ChunkUnloadReloadRoundtripGameTests.java
@@ -6,8 +6,8 @@
import com.talhanation.bannermod.persistence.military.RecruitsClaim;
import com.talhanation.bannermod.persistence.military.RecruitsClaimSaveData;
import com.talhanation.bannermod.persistence.military.RecruitsPlayerInfo;
-import com.talhanation.bannermod.settlement.BannerModSettlementManager;
-import com.talhanation.bannermod.settlement.BannerModSettlementSnapshot;
+import com.talhanation.bannermod.settlement.SettlementManager;
+import com.talhanation.bannermod.settlement.SettlementSnapshot;
import net.minecraft.core.HolderLookup;
import net.minecraft.gametest.framework.GameTest;
import net.minecraft.gametest.framework.GameTestHelper;
@@ -48,7 +48,7 @@
* roundtrip test ({@code claimRoundtripTagIsByteForByteIdentical}).
* Settlement snapshot's serialized tag via {@code toTag}/{@code equals}
* — covered both at the record level and through the
- * {@link BannerModSettlementManager} SavedData.
+ * {@link SettlementManager} SavedData.
* Treasury ledger — covered by the
* {@link BannerModTreasuryManager} roundtrip test.
* Per-chunk SavedData — the three SavedData entries above are the
@@ -67,7 +67,7 @@ public class ChunkUnloadReloadRoundtripGameTests {
@GameTest(template = "harness_empty")
public static void settlementSnapshotTagIsByteForByteIdenticalAfterRoundtrip(GameTestHelper helper) {
UUID claimUuid = UUID.fromString("11111111-2222-3333-4444-555555555555");
- BannerModSettlementSnapshot snapshot = BannerModSettlementSnapshot.create(
+ SettlementSnapshot snapshot = SettlementSnapshot.create(
claimUuid,
ANCHOR_CHUNK,
"test-faction"
@@ -77,7 +77,7 @@ public static void settlementSnapshotTagIsByteForByteIdenticalAfterRoundtrip(Gam
CompoundTag preUnloadTag = snapshot.toTag();
// Simulated unload + reload: re-hydrate via the production fromTag entry.
- BannerModSettlementSnapshot reloaded = BannerModSettlementSnapshot.fromTag(preUnloadTag);
+ SettlementSnapshot reloaded = SettlementSnapshot.fromTag(preUnloadTag);
// Post-reload: re-serialize through the same toTag entry point.
CompoundTag postReloadTag = reloaded.toTag();
@@ -199,12 +199,12 @@ public static void claimSettlementAndTreasuryAllSurviveSimulatedChunkUnloadReloa
RecruitsClaimSaveData claimData = new RecruitsClaimSaveData();
claimData.setAllClaims(List.of(claim));
- BannerModSettlementSnapshot snapshot = BannerModSettlementSnapshot.create(
+ SettlementSnapshot snapshot = SettlementSnapshot.create(
coherentClaimUuid,
ANCHOR_CHUNK,
"test-faction"
);
- BannerModSettlementManager settlementManager = new BannerModSettlementManager();
+ SettlementManager settlementManager = new SettlementManager();
settlementManager.putSnapshot(snapshot);
BannerModTreasuryLedgerSnapshot ledger = BannerModTreasuryLedgerSnapshot
@@ -222,8 +222,8 @@ public static void claimSettlementAndTreasuryAllSurviveSimulatedChunkUnloadReloa
// ----- Simulated chunk unload/reload: production load() then save() again.
RecruitsClaimSaveData claimReloaded =
RecruitsClaimSaveData.load(claimPreTag, registries);
- BannerModSettlementManager settlementReloaded =
- BannerModSettlementManager.load(settlementPreTag, registries);
+ SettlementManager settlementReloaded =
+ SettlementManager.load(settlementPreTag, registries);
BannerModTreasuryManager treasuryReloaded =
BannerModTreasuryManager.load(treasuryPreTag, registries);
@@ -236,7 +236,7 @@ public static void claimSettlementAndTreasuryAllSurviveSimulatedChunkUnloadReloa
helper.assertTrue(reloadedClaim.containsChunk(ANCHOR_CHUNK),
"Claim chunk coord must survive unload/reload");
- BannerModSettlementSnapshot reloadedSnapshot = settlementReloaded.getSnapshot(coherentClaimUuid);
+ SettlementSnapshot reloadedSnapshot = settlementReloaded.getSnapshot(coherentClaimUuid);
helper.assertTrue(reloadedSnapshot != null,
"Settlement snapshot must be reachable by claim UUID after reload");
helper.assertTrue(snapshotPreTag.equals(reloadedSnapshot.toTag()),
diff --git a/src/main/java/com/talhanation/bannermod/ai/civilian/AnimalFarmerWorkGoal.java b/src/main/java/com/talhanation/bannermod/ai/civilian/AnimalFarmerWorkGoal.java
deleted file mode 100644
index 5ab19966..00000000
--- a/src/main/java/com/talhanation/bannermod/ai/civilian/AnimalFarmerWorkGoal.java
+++ /dev/null
@@ -1,614 +0,0 @@
-package com.talhanation.bannermod.ai.civilian;
-
-import com.talhanation.bannermod.entity.civilian.AnimalFarmerEntity;
-import com.talhanation.bannermod.entity.civilian.WorkerBindingResume;
-import com.talhanation.bannermod.entity.civilian.workarea.AnimalPenArea;
-import com.talhanation.bannermod.persistence.civilian.NeededItem;
-import net.minecraft.network.chat.Component;
-import net.minecraft.server.level.ServerLevel;
-import net.minecraft.sounds.SoundEvents;
-import net.minecraft.sounds.SoundSource;
-import net.minecraft.world.InteractionHand;
-import net.minecraft.world.entity.ai.goal.Goal;
-import net.minecraft.world.entity.animal.Animal;
-import net.minecraft.world.entity.animal.Sheep;
-import net.minecraft.world.entity.projectile.ThrownEgg;
-import net.minecraft.world.item.AxeItem;
-import net.minecraft.world.item.Item;
-import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.item.Items;
-import net.minecraft.world.phys.Vec3;
-
-import javax.annotation.Nullable;
-import java.util.*;
-
-public class AnimalFarmerWorkGoal extends Goal {
-
- private static final int AREA_SEARCH_COOLDOWN_TICKS = 20;
- private static final int PATH_REQUEST_COOLDOWN_TICKS = 20;
-
- public AnimalFarmerEntity animalFarmerEntity;
- public State state;
- public boolean errorMessageDone;
- public Animal animal;
- public AnimalPenArea.AnimalTypes animalType;
- public int amountToBreed;
- public int amountToSlaughter;
- public Stack stackOfAnimals = new Stack<>();
- public List neededItems = new ArrayList<>();
- public int time;
- public boolean isHolding;
- private int lastAreaSearchTick = -AREA_SEARCH_COOLDOWN_TICKS;
- private int lastPathRequestTick = -PATH_REQUEST_COOLDOWN_TICKS;
- @Nullable
- private Vec3 lastPathRequestPos;
-
- public AnimalFarmerWorkGoal(AnimalFarmerEntity animalFarmerEntity) {
- this.animalFarmerEntity = animalFarmerEntity;
- setFlags(EnumSet.of(Flag.LOOK, Flag.MOVE));
- }
-
- @Override
- public boolean canUse() {
- return !animalFarmerEntity.needsToSleep() && animalFarmerEntity.shouldWork() && !animalFarmerEntity.needsToGetToChest();
- }
-
- @Override
- public void start() {
- super.start();
- if(this.animalFarmerEntity.getCommandSenderWorld().isClientSide()) return;
- animalFarmerEntity.setAggroState(3);
- setState(State.SELECT_WORK_AREA);
- }
-
- @Override
- public void stop() {
- super.stop();
- animalFarmerEntity.setAggroState(0);
- clearCurrentPenBusyState();
- }
-
- @Override
- public void tick() {
- super.tick();
- if(this.animalFarmerEntity.getCommandSenderWorld().isClientSide()) return;
- if(state == null) return;
- if(state != State.SELECT_WORK_AREA && !hasUsableCurrentPen()) {
- discardInvalidCurrentPen();
- setState(State.SELECT_WORK_AREA);
- return;
- }
- if(animal != null) this.animalFarmerEntity.getLookControl().setLookAt(animal);
- if(this.animalFarmerEntity.tickCount % 20 != 0) return;
-
- switch(state){
- case SELECT_WORK_AREA ->{
- if(hasUsableCurrentPen()) {
- prepareCurrentPen();
- setState(State.MOVE_TO_WORK_AREA);
- return;
- }
-
- discardInvalidCurrentPen();
-
- if(animalFarmerEntity.tickCount - lastAreaSearchTick < AREA_SEARCH_COOLDOWN_TICKS) return;
- lastAreaSearchTick = animalFarmerEntity.tickCount;
-
- List areas = getAvailableWorkAreasByPriority((ServerLevel) animalFarmerEntity.getCommandSenderWorld(), animalFarmerEntity, animalFarmerEntity.getCurrentAnimalPen());
-
- if (!areas.isEmpty()) {
- this.animalFarmerEntity.setCurrentWorkArea(areas.get(0));
- }
-
- if(this.animalFarmerEntity.getCurrentAnimalPen() == null) {
- animalFarmerEntity.reportIdleReason("animal_farmer_no_pen", Component.literal(animalFarmerEntity.getName().getString() + ": Waiting for an animal pen."));
- return;
- }
-
- prepareCurrentPen();
-
- setState(State.MOVE_TO_WORK_AREA);
- }
-
- case MOVE_TO_WORK_AREA ->{
- this.animal = null;
- if(this.moveToPosition(animalFarmerEntity.getCurrentAnimalPen().position(), 100)) return;
-
- setState(State.MOVE_TO_CENTER);
- }
-
- case MOVE_TO_CENTER ->{
- this.animal = null;
- if(this.moveToPosition(animalFarmerEntity.getCurrentAnimalPen().position(), 30)) return;
-
- setState(State.PREPARE_BREED);
- }
-
- case PREPARE_BREED -> {
- if(!animalFarmerEntity.getCurrentAnimalPen().getBreed() || !animalFarmerEntity.getCurrentAnimalPen().isBreedTime()){
- applyLoopDecision(AnimalFarmerLoopProgress.selectNextAction(false, false, 0,
- animalFarmerEntity.getCurrentAnimalPen().getSpecial(), 1,
- animalType == AnimalPenArea.AnimalTypes.CHICKEN,
- animalFarmerEntity.getCurrentAnimalPen().getSlaughter(),
- animalFarmerEntity.getCurrentAnimalPen().animalsToSlaughter.size(),
- animalFarmerEntity.getCurrentAnimalPen().getMaxAnimals()));
- return;
- }
-
- animalFarmerEntity.getCurrentAnimalPen().scanAnimalBreed();
- this.stackOfAnimals = animalFarmerEntity.getCurrentAnimalPen().animalsToBreed;
-
- if(stackOfAnimals.isEmpty()){
- setState(State.PREPARE_SPECIAL_TASK);
- return;
- }
-
- amountToBreed = stackOfAnimals.size();
- amountToBreed -= amountToBreed % 2;
-
- Item breedItem = animalType.getBreedItem();
- animalFarmerEntity.switchMainHandItem(itemStack -> itemStack.is(breedItem));
- ItemStack mainHandItem = animalFarmerEntity.getMainHandItem();
-
- boolean hasBreedItem = mainHandItem.is(breedItem);
- if(!hasBreedItem){
- animalFarmerEntity.requestRequiredItem(new NeededItem(stack -> stack.is(breedItem), amountToBreed, true),
- "animal_farmer_missing_breed_item",
- Component.literal(animalFarmerEntity.getName().getString() + ": I need breeding items to continue."));
- this.animal = null;
- applyLoopDecision(AnimalFarmerLoopProgress.waitForRequiredItem(AnimalFarmerLoopProgress.Action.PREPARE_BREED));
- return;
- }
-
- setState(State.BREED);
- }
-
- case BREED -> {
- if(animalFarmerEntity.getCurrentAnimalPen().getBreed() && animalFarmerEntity.getCurrentAnimalPen().isBreedTime() && this.breed()) return;
-
- this.animalFarmerEntity.getCurrentAnimalPen().setBreedTime(2000);
- applyLoopDecision(AnimalFarmerLoopProgress.selectNextAction(false, false, 0,
- animalFarmerEntity.getCurrentAnimalPen().getSpecial(), 1,
- animalType == AnimalPenArea.AnimalTypes.CHICKEN,
- animalFarmerEntity.getCurrentAnimalPen().getSlaughter(),
- animalFarmerEntity.getCurrentAnimalPen().animalsToSlaughter.size(),
- animalFarmerEntity.getCurrentAnimalPen().getMaxAnimals()));
- }
-
- case PREPARE_SPECIAL_TASK -> {
- if(!animalFarmerEntity.getCurrentAnimalPen().getSpecial()){
- applyLoopDecision(AnimalFarmerLoopProgress.selectNextAction(false, false, 0,
- false, 0, false,
- animalFarmerEntity.getCurrentAnimalPen().getSlaughter(),
- animalFarmerEntity.getCurrentAnimalPen().animalsToSlaughter.size(),
- animalFarmerEntity.getCurrentAnimalPen().getMaxAnimals()));
- return;
- }
-
- if(!animalFarmerEntity.hasFreeInvSlot()){
- animalFarmerEntity.forcedDeposit = true;
- applyLoopDecision(AnimalFarmerLoopProgress.waitForDeposit(AnimalFarmerLoopProgress.Action.PREPARE_SPECIAL_TASK));
- return;
- }
-
- this.animalFarmerEntity.getCurrentAnimalPen().scanAnimalSpecial();
- this.stackOfAnimals = animalFarmerEntity.getCurrentAnimalPen().animalsForSpecialTask;
-
- if(stackOfAnimals.isEmpty() && animalType != AnimalPenArea.AnimalTypes.CHICKEN){
- applyLoopDecision(AnimalFarmerLoopProgress.selectNextAction(false, false, 0,
- false, 0, false,
- animalFarmerEntity.getCurrentAnimalPen().getSlaughter(),
- animalFarmerEntity.getCurrentAnimalPen().animalsToSlaughter.size(),
- animalFarmerEntity.getCurrentAnimalPen().getMaxAnimals()));
- return;
- }
- setState(State.SPECIAL_TASK);
- }
-
- case SPECIAL_TASK -> {
- if(animalFarmerEntity.getCurrentAnimalPen().getSpecial() && this.doSpecialTask()) return;
- applyLoopDecision(AnimalFarmerLoopProgress.selectNextAction(false, false, 0,
- false, 0, false,
- animalFarmerEntity.getCurrentAnimalPen().getSlaughter(),
- animalFarmerEntity.getCurrentAnimalPen().animalsToSlaughter.size(),
- animalFarmerEntity.getCurrentAnimalPen().getMaxAnimals()));
- }
-
- case PREPARE_SLAUGHTER -> {
- if(!animalFarmerEntity.getCurrentAnimalPen().getSlaughter()){
- applyLoopDecision(AnimalFarmerLoopProgress.selectNextAction(false, false, 0,
- false, 0, false,
- false, 0,
- animalFarmerEntity.getCurrentAnimalPen().getMaxAnimals()));
- return;
- }
-
- if(!animalFarmerEntity.hasFreeInvSlot()){
- animalFarmerEntity.forcedDeposit = true;
- applyLoopDecision(AnimalFarmerLoopProgress.waitForDeposit(AnimalFarmerLoopProgress.Action.PREPARE_SLAUGHTER));
- return;
- }
-
- this.animalFarmerEntity.getCurrentAnimalPen().scanAnimalSlaughter();
- this.stackOfAnimals = animalFarmerEntity.getCurrentAnimalPen().animalsToSlaughter;
-
- int max = animalFarmerEntity.getCurrentAnimalPen().getMaxAnimals();
- int size = stackOfAnimals.size();
-
- if(max >= size){
- applyLoopDecision(AnimalFarmerLoopProgress.selectNextAction(false, false, 0,
- false, 0, false,
- true, size,
- max));
- return;
- }
-
- amountToSlaughter = size - max;
-
- animalFarmerEntity.switchMainHandItem(itemStack -> itemStack.getItem() instanceof AxeItem);
-
- boolean hasAxe = animalFarmerEntity.getMainHandItem().getItem() instanceof AxeItem;
- if(!hasAxe){
- animalFarmerEntity.requestRequiredItem(new NeededItem(stack -> stack.getItem() instanceof AxeItem, 1, true),
- "animal_farmer_missing_axe",
- Component.literal(animalFarmerEntity.getName().getString() + ": I need an axe to continue."));
- this.animal = null;
- applyLoopDecision(AnimalFarmerLoopProgress.waitForRequiredItem(AnimalFarmerLoopProgress.Action.PREPARE_SLAUGHTER));
- return;
- }
-
- setState(State.SLAUGHTER);
- }
- case SLAUGHTER -> {
- if(animalFarmerEntity.getCurrentAnimalPen().getSlaughter() && this.slaughter()) return;
-
- applyLoopDecision(AnimalFarmerLoopProgress.selectNextAction(false, false, 0,
- false, 0, false,
- false, 0,
- animalFarmerEntity.getCurrentAnimalPen().getMaxAnimals()));
- }
-
- case DONE -> {
- finishCurrentPen();
- animalFarmerEntity.switchMainHandItem(ItemStack::isEmpty);
- animalFarmerEntity.clearWorkStatus();
- setState(State.SELECT_WORK_AREA);
-
- if(!this.neededItems.isEmpty()){
- for(NeededItem neededItem : neededItems){
- this.animalFarmerEntity.addNeededItem(neededItem);
- }
- this.neededItems.clear();
- }
- }
-
- case ERROR ->{
- if(!errorMessageDone){
- errorMessageDone = true;
- }
-
- if(++time > 1000){
- time = 0;
- this.start();
- }
-
- }
- }
- }
-
- private boolean breed() {
- if(this.animal == null) {
- if(!stackOfAnimals.isEmpty()) animal = stackOfAnimals.pop();
- else return false;
- }
- if(this.moveToPosition(animal.position(), 6)) return true;
- this.animalFarmerEntity.getLookControl().setLookAt(animal);
-
- Item breedItem = animalType.getBreedItem();
- animalFarmerEntity.switchMainHandItem(itemStack -> itemStack.is(breedItem));
- ItemStack mainHandItem = animalFarmerEntity.getMainHandItem();
-
- boolean hasBreedItem = mainHandItem.is(breedItem);
- if(!hasBreedItem){
- animalFarmerEntity.addNeededItem(new NeededItem(stack -> stack.is(breedItem), amountToBreed, false));
- this.animal = null;
- return false;
- }
-
- this.animalFarmerEntity.swing(InteractionHand.MAIN_HAND);
- this.animalFarmerEntity.getMainHandItem().shrink(1);
- amountToBreed--;
- animal.setAge(0);
-
- animal.setInLove(null);
-
- this.animal = null;
- return true;
- }
-
- private boolean doSpecialTask() {
- Item specialItem = animalType.getSpecialItem();
-
- animalFarmerEntity.switchMainHandItem(itemStack -> itemStack.is(specialItem));
-
- ItemStack mainHandItem = animalFarmerEntity.getMainHandItem();
-
- boolean hasSpecialItem = mainHandItem.is(specialItem);
- if(!hasSpecialItem){
- boolean chicken = animalType == AnimalPenArea.AnimalTypes.CHICKEN;
-
- animalFarmerEntity.requestRequiredItem(new NeededItem(stack -> stack.is(specialItem), chicken ? 32 : 1, !chicken),
- "animal_farmer_missing_special_item",
- Component.literal(animalFarmerEntity.getName().getString() + ": I need the right tool or item to continue."));
- this.animal = null;
- applyLoopDecision(AnimalFarmerLoopProgress.waitForRequiredItem(AnimalFarmerLoopProgress.Action.PREPARE_SPECIAL_TASK));
- return true;
- }
- if(animalType == AnimalPenArea.AnimalTypes.CHICKEN){
-
- return throwEggs();
- }
-
- if(this.animal == null) {
- if(!stackOfAnimals.isEmpty()) animal = stackOfAnimals.pop();
- else return false;
- }
- if(this.moveToPosition(animal.position(), 6)) return true;
-
- if(animalType == AnimalPenArea.AnimalTypes.SHEEP){
- return sheerSheep();
- } else if (animalType == AnimalPenArea.AnimalTypes.COW) {
- return milkCow();
- }
-
- return false;
- }
-
- public boolean slaughter() {
- animalFarmerEntity.switchMainHandItem(itemStack -> itemStack.getItem() instanceof AxeItem);
-
- boolean hasAxe = animalFarmerEntity.getMainHandItem().getItem() instanceof AxeItem;
- if(!hasAxe){
- animalFarmerEntity.requestRequiredItem(new NeededItem(stack -> stack.getItem() instanceof AxeItem, 1, true),
- "animal_farmer_missing_axe",
- Component.literal(animalFarmerEntity.getName().getString() + ": I need an axe to continue."));
- this.animal = null;
- applyLoopDecision(AnimalFarmerLoopProgress.waitForRequiredItem(AnimalFarmerLoopProgress.Action.PREPARE_SLAUGHTER));
- return false;
- }
-
- int max = animalFarmerEntity.getCurrentAnimalPen().getMaxAnimals();
- int size = stackOfAnimals.size();
-
- if(max >= size || amountToSlaughter == 0){
- setState(State.DONE);
- return false;
- }
-
- if(this.animal == null) {
- if(!stackOfAnimals.isEmpty()) animal = stackOfAnimals.pop();
- else return false;
- }
-
- if(this.moveToPosition(animal.position(), 6)) return true;
- this.animalFarmerEntity.getLookControl().setLookAt(animal);
-
- animalFarmerEntity.playSound(SoundEvents.PLAYER_ATTACK_STRONG);
- this.animalFarmerEntity.swing(InteractionHand.MAIN_HAND);
-
- animal.kill();
- amountToSlaughter--;
-
- animalFarmerEntity.damageMainHandItem();
-
- animal = null;
- return true;
- }
-
-
- private boolean throwEggs() {
- if(!this.animalFarmerEntity.getMainHandItem().is(Items.EGG)){
- return false;
- }
- if(this.moveToPosition(animalFarmerEntity.getCurrentAnimalPen().getArea().getCenter(), 10)){
- return true;
- }
-
- animalFarmerEntity.getCommandSenderWorld().playSound(null, animalFarmerEntity.getX(), animalFarmerEntity.getY(), animalFarmerEntity.getZ(), SoundEvents.EGG_THROW, SoundSource.PLAYERS, 0.5F, 0.4F / (animalFarmerEntity.getRandom().nextFloat() * 0.4F + 0.8F));
- ThrownEgg thrownegg = new ThrownEgg(animalFarmerEntity.getCommandSenderWorld(), animalFarmerEntity);
- thrownegg.setItem(new ItemStack(Items.EGG));
-
- double d0 = animalFarmerEntity.getCurrentAnimalPen().getArea().getCenter().x() - this.animalFarmerEntity.getX();
- double d2 = animalFarmerEntity.getCurrentAnimalPen().getArea().getCenter().z() - this.animalFarmerEntity.getZ();
-
- thrownegg.shoot(d0, 0, d2, 0.1F, 0F);
-
- if(animalFarmerEntity.getCommandSenderWorld().addFreshEntity(thrownegg)){
- this.animalFarmerEntity.getMainHandItem().shrink(1);
- }
-
- return true;
- }
-
- public boolean sheerSheep() {
- if(animal == null) return false;
-
- if(animal instanceof Sheep sheep){
- sheep.shear(SoundSource.PLAYERS);
- sheep.setSheared(true);
-
- this.animalFarmerEntity.swing(InteractionHand.MAIN_HAND);
- this.animalFarmerEntity.damageMainHandItem();
- }
- this.animal = null;
- return true;
- }
-
- public boolean milkCow() {
- if(animal == null) return false;
-
- animalFarmerEntity.getMainHandItem().shrink(1);
- animalFarmerEntity.getInventory().addItem(Items.MILK_BUCKET.getDefaultInstance());
- animal.playSound(SoundEvents.COW_MILK, 1.0F, 1.0F);
-
- animal = null;
- return true;
- }
-
- public void setState(State state) {
- this.state = state;
- }
-
- private void applyLoopDecision(AnimalFarmerLoopProgress.Decision decision) {
- if (decision == null) {
- return;
- }
-
- switch (decision.action()) {
- case PREPARE_BREED -> setState(State.PREPARE_BREED);
- case PREPARE_SPECIAL_TASK -> setState(State.PREPARE_SPECIAL_TASK);
- case PREPARE_SLAUGHTER -> setState(State.PREPARE_SLAUGHTER);
- case WAIT_FOR_ITEM, WAIT_FOR_DEPOSIT -> setState(mapActionToState(decision.resumeAction()));
- case FINISHED -> setState(State.DONE);
- }
- }
-
- private State mapActionToState(AnimalFarmerLoopProgress.Action action) {
- return switch (action) {
- case PREPARE_BREED -> State.PREPARE_BREED;
- case PREPARE_SPECIAL_TASK -> State.PREPARE_SPECIAL_TASK;
- case PREPARE_SLAUGHTER -> State.PREPARE_SLAUGHTER;
- case WAIT_FOR_ITEM, WAIT_FOR_DEPOSIT, FINISHED -> state;
- };
- }
-
- private boolean hasUsableCurrentPen() {
- return this.animalFarmerEntity.getCurrentAnimalPen() != null
- && !this.animalFarmerEntity.getCurrentAnimalPen().isRemoved()
- && this.animalFarmerEntity.getCurrentAnimalPen().canWorkHere(this.animalFarmerEntity);
- }
-
- private void prepareCurrentPen() {
- if (!hasUsableCurrentPen()) {
- return;
- }
-
- animalFarmerEntity.clearWorkStatus();
- this.animalFarmerEntity.getCurrentAnimalPen().setBeingWorkedOn(true);
- this.animalFarmerEntity.getCurrentAnimalPen().setTime(0);
- this.animalType = this.animalFarmerEntity.getCurrentAnimalPen().getAnimalType();
- }
-
- private void clearCurrentPenBusyState() {
- if (this.animalFarmerEntity.getCurrentAnimalPen() != null) {
- this.animalFarmerEntity.getCurrentAnimalPen().setBeingWorkedOn(false);
- }
- }
-
- private void discardInvalidCurrentPen() {
- clearCurrentPenBusyState();
- this.animalFarmerEntity.setCurrentWorkArea(null);
- this.animal = null;
- }
-
- private void finishCurrentPen() {
- clearCurrentPenBusyState();
- this.animalFarmerEntity.setCurrentWorkArea(null);
- this.animal = null;
- }
-
- @Override
- public boolean canContinueToUse() {
- return canUse() || this.isHolding;
- }
-
- @Override
- public boolean isInterruptable() {
- return true;
- }
-
- @Override
- public boolean requiresUpdateEveryTick() {
- return true;
- }
-
- public static List getAvailableWorkAreasByPriority(ServerLevel level, AnimalFarmerEntity animalFarmerEntity, @Nullable AnimalPenArea currentArea) {
- List list = com.talhanation.bannermod.entity.civilian.workarea.WorkAreaIndex.instance()
- .queryInRange(animalFarmerEntity, 64, AnimalPenArea.class);
-
- Map priorityMap = new HashMap<>();
-
- for (AnimalPenArea area : list) {
- if (area == null || area == currentArea || !area.canWorkHere(animalFarmerEntity)) continue;
-
- int priority = 0;
-
- boolean perfectCandidate = area.isWorkerPerfectCandidate(animalFarmerEntity);
-
- if (perfectCandidate) {
- priority += 10;
- } else {
- priority += 1;
- }
-
- if (!area.isBeingWorkedOn()) {
- priority += 3;
- }
-
- priority += area.time;
- priority += WorkerBindingResume.priorityBoost(animalFarmerEntity.getBoundWorkAreaUUID(), area.getUUID());
-
- priorityMap.put(area, priority);
- }
-
- List sorted = new ArrayList<>(priorityMap.keySet());
- sorted.sort((a, b) -> Integer.compare(priorityMap.get(b), priorityMap.get(a)));
-
- return sorted;
- }
-
- public boolean moveToPosition(Vec3 pos, int threshold){
- if(pos == null){
- return false;
- }
- else{
- double distance = animalFarmerEntity.getHorizontalDistanceTo(pos);
- if(distance < threshold){
- lastPathRequestPos = null;
- return false;
- }
- else{
- if(shouldRequestPath(pos)){
- animalFarmerEntity.getNavigation().moveTo(pos.x(), pos.y(), pos.z(), 0.8F);
- }
- animalFarmerEntity.setFollowState(6); //Working
- animalFarmerEntity.getLookControl().setLookAt(pos);
- }
- return true;
- }
- }
-
- private boolean shouldRequestPath(Vec3 pos) {
- if(!pos.equals(lastPathRequestPos) || animalFarmerEntity.tickCount - lastPathRequestTick >= PATH_REQUEST_COOLDOWN_TICKS){
- lastPathRequestPos = pos;
- lastPathRequestTick = animalFarmerEntity.tickCount;
- return true;
- }
- return false;
- }
-
- public enum State{
- SELECT_WORK_AREA,
- MOVE_TO_WORK_AREA,
- MOVE_TO_CENTER,
- PREPARE_BREED,
- BREED,
- PREPARE_SLAUGHTER,
- SLAUGHTER,
- PREPARE_SPECIAL_TASK,
- SPECIAL_TASK,
- DONE,
- ERROR;
-
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/ai/civilian/BuilderWorkGoal.java b/src/main/java/com/talhanation/bannermod/ai/civilian/BuilderWorkGoal.java
deleted file mode 100644
index 9a6e8abc..00000000
--- a/src/main/java/com/talhanation/bannermod/ai/civilian/BuilderWorkGoal.java
+++ /dev/null
@@ -1,662 +0,0 @@
-package com.talhanation.bannermod.ai.civilian;
-
-import com.talhanation.bannermod.entity.civilian.BuilderEntity;
-import com.talhanation.bannermod.entity.civilian.WorkerBindingResume;
-import com.talhanation.bannermod.entity.civilian.workarea.AbstractWorkAreaEntity;
-import com.talhanation.bannermod.entity.civilian.workarea.BuildArea;
-import com.talhanation.bannermod.persistence.civilian.BuildBlock;
-import com.talhanation.bannermod.persistence.civilian.BuildBlockParse;
-import com.talhanation.bannermod.persistence.civilian.NeededItem;
-import com.talhanation.bannermod.shared.settlement.BannerModSettlementRefreshSupport;
-import net.minecraft.core.BlockPos;
-import net.minecraft.core.Direction;
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.nbt.ListTag;
-import net.minecraft.nbt.Tag;
-import net.minecraft.network.chat.Component;
-import net.minecraft.resources.ResourceLocation;
-import net.minecraft.server.level.ServerLevel;
-import net.minecraft.sounds.SoundEvents;
-import net.minecraft.sounds.SoundSource;
-import net.minecraft.world.InteractionHand;
-import net.minecraft.world.entity.Entity;
-import net.minecraft.world.entity.EntityType;
-import net.minecraft.world.entity.ai.goal.Goal;
-import net.minecraft.world.item.BlockItem;
-import net.minecraft.world.item.Item;
-import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.item.DiggerItem;
-import net.minecraft.world.item.PickaxeItem;
-import net.minecraft.world.level.ClipContext;
-import net.minecraft.world.level.Level;
-import net.minecraft.world.level.block.Block;
-import net.minecraft.world.level.block.Blocks;
-import net.minecraft.world.level.block.state.BlockState;
-import net.minecraft.world.level.material.FluidState;
-import net.minecraft.world.phys.Vec3;
-import net.minecraft.core.registries.BuiltInRegistries;
-
-import javax.annotation.Nullable;
-import java.util.*;
-import java.util.stream.Collectors;
-
-public class BuilderWorkGoal extends Goal {
-
- private static final int AREA_SEARCH_COOLDOWN_TICKS = 20;
- private static final int PATH_REQUEST_COOLDOWN_TICKS = 20;
-
- public BuilderEntity builderEntity;
- public State state;
- public String errorMessage;
- public boolean errorMessageDone;
- public BlockPos blockPos;
- public Stack stackToBreak;
- public Stack stackToPlace;
- public int minBuildHeight;
- private int lastAreaSearchTick = -AREA_SEARCH_COOLDOWN_TICKS;
- private int lastPathRequestTick = -PATH_REQUEST_COOLDOWN_TICKS;
- @Nullable
- private BlockPos lastPathRequestPos;
-
- public BuilderWorkGoal(BuilderEntity builderEntity) {
- this.builderEntity = builderEntity;
- setFlags(EnumSet.of(Flag.LOOK, Flag.MOVE));
- }
-
- @Override
- public boolean canUse() {
- return !builderEntity.needsToSleep() && builderEntity.shouldWork() && !builderEntity.needsToGetToChest() && this.isBuildingAreaAvailable();
- }
-
- @Override
- public void start() {
- super.start();
- if(this.builderEntity.getCommandSenderWorld().isClientSide()) return;
-
-
- setState(State.SELECT_WORK_AREA);
- }
- boolean workDone;
- @Override
- public void tick() {
- super.tick();
- if(this.builderEntity.getCommandSenderWorld().isClientSide()) return;
- if(state == null) return;
- if(blockPos != null) this.builderEntity.getLookControl().setLookAt(blockPos.getCenter());
-
- if(!isBuildingAreaAvailable()) return;
-
- if(state != State.SELECT_WORK_AREA && this.builderEntity.getCurrentBuildArea() == null){
- this.blockPos = null;
- setState(State.SELECT_WORK_AREA);
- return;
- }
-
- if(blockPos != null && moveToPosition(blockPos, 40)) return;
-
- if(state == State.BREAK_BLOCKS){
- if(this.mineBlocks(this.stackToBreak)) return;
-
- setState(State.PREPARE_PLACE_BLOCKS);
- }
-
- if(builderEntity.tickCount % 5 != 0) return;
- switch(state){
- case SELECT_WORK_AREA ->{
- if(builderEntity.getCurrentBuildArea() != null) setState(State.MOVE_TO_WORK_AREA);
-
- if(builderEntity.tickCount - lastAreaSearchTick < AREA_SEARCH_COOLDOWN_TICKS) return;
- lastAreaSearchTick = builderEntity.tickCount;
-
- List areas = getAvailableWorkAreasByPriority((ServerLevel) builderEntity.getCommandSenderWorld(), builderEntity, builderEntity.getCurrentBuildArea());
-
- if (!areas.isEmpty()) {
- builderEntity.setCurrentWorkArea(areas.get(0));
- }
-
- if(builderEntity.getCurrentBuildArea() == null) {
- builderEntity.reportIdleReason("builder_no_area", Component.literal(builderEntity.getName().getString() + ": Waiting for a build area."));
- return;
- }
-
- builderEntity.clearWorkStatus();
- builderEntity.getCurrentBuildArea().setBeingWorkedOn(true);
- this.builderEntity.getCurrentBuildArea().setTime(0);
- workDone = false;
- setState(State.MOVE_TO_WORK_AREA);
- }
-
- case MOVE_TO_WORK_AREA ->{
- this.blockPos = null;
- if(this.moveToPosition(builderEntity.getCurrentBuildArea().getOnPos(), 70)) return;
-
- setState(State.PREPARE_BREAK_BLOCKS);
- }
-
- case PREPARE_BREAK_BLOCKS -> {
- this.builderEntity.getCurrentBuildArea().scanBreakArea();//SOMETHING WRONG I CAN FEEL IT
-
- this.stackToBreak = this.builderEntity.getCurrentBuildArea().stackToBreak;
-
- if(stackToBreak.isEmpty()){
- setState(State.PREPARE_PLACE_BLOCKS);
- return;
- }
-
- boolean hasDigger = builderEntity.getInventory().hasAnyMatching(
- itemStack -> itemStack.getItem() instanceof DiggerItem);
- if (!hasDigger) {
- builderEntity.requestRequiredItem(new NeededItem(
- stack -> stack.getItem() instanceof PickaxeItem, 1, true),
- "builder_missing_tool",
- Component.literal(builderEntity.getName().getString() + ": I need digging tools to continue."));
- this.blockPos = null;
- return;
- }
- if (!stackToBreak.isEmpty()) {
- BlockState firstState = builderEntity.getCommandSenderWorld()
- .getBlockState(stackToBreak.peek());
- builderEntity.changeTool(firstState);
- }
- setState(State.BREAK_BLOCKS);
- }
-
- case PREPARE_PLACE_BLOCKS -> {
- if (builderEntity.getCurrentBuildArea().stackToPlace.isEmpty()) {
- if (!builderEntity.getCurrentBuildArea().stackToPlaceMultiBlock.isEmpty()) {
- setState(State.PREPARE_PLACE_MULTIBLOCK);
- } else {
- setState(State.DONE);
- }
- return;
- }
-
- minBuildHeight = (int) builderEntity.getCurrentBuildArea().getArea().maxY;
-
- for (BuildBlock bb : builderEntity.getCurrentBuildArea().stackToPlace) {
- int y = bb.getPos().getY();
- if (y < minBuildHeight) {
- minBuildHeight = y;
- }
- }
-
-
- this.stackToPlace = new Stack<>();
- for (BuildBlock buildBlock : builderEntity.getCurrentBuildArea().stackToPlace) {
- BlockPos pos = buildBlock.getPos();
- if (pos.getY() != minBuildHeight) continue;
-
- Item item = BuildBlockParse.parseBlock(buildBlock.getState().getBlock()).getItem();
- if(item == null){
- if(builderEntity.getOwner() != null) builderEntity.getOwner().sendSystemMessage(Component.literal("Could not found item for " + buildBlock.getState().getBlock().getName() + " i, will skip this block." ));
- builderEntity.getCurrentBuildArea().removeBuildBlockToPlace(pos);
- return;
- }
- else if (builderEntity.getInventory().hasAnyMatching(itemStack -> itemStack.is(item))) {
- stackToPlace.push(pos);
- }
- }
-
- if (stackToPlace.isEmpty()) {
- List neededItems = builderEntity.getCurrentBuildArea().getRequiredMaterials();
- neededItems.sort(Comparator.comparingInt(ItemStack::getCount).reversed());
-
- Set- allowedItems = builderEntity.getCurrentBuildArea().stackToPlace.stream()
- .filter(bb -> bb.getPos().getY() == minBuildHeight)
- .map(bb -> BuildBlockParse.parseBlock(bb.getState().getBlock()).getItem())
- .collect(Collectors.toSet());
-
- neededItems.removeIf(stack -> !allowedItems.contains(stack.getItem()));
-
- if (!neededItems.isEmpty()) {
- ItemStack neededItem = neededItems.get(0);
- int amount = Math.min(64, neededItem.getCount());
-
- builderEntity.requestRequiredItem(new NeededItem(
- itemStack -> itemStack.is(neededItem.getItem()), amount, true
- ),
- "builder_missing_materials",
- Component.literal(builderEntity.getName().getString() + ": I need more building materials."));
- }
- }
-
- setState(State.PLACE_BLOCKS);
- }
-
-
- case PLACE_BLOCKS -> {
- if(this.placeBlocks(this.stackToPlace)) return;
-
- setState(State.PREPARE_PLACE_BLOCKS);
- }
-
- case PREPARE_PLACE_MULTIBLOCK -> {
- if (builderEntity.getCurrentBuildArea().stackToPlaceMultiBlock.isEmpty()) {
- setState(State.DONE);
- return;
- }
-
- this.stackToPlace = new Stack<>();
- for (BuildBlock bb : builderEntity.getCurrentBuildArea().stackToPlaceMultiBlock) {
- stackToPlace.push(bb.getPos());
- }
-
- setState(State.PLACE_MULTIBLOCK);
- }
-
- case PLACE_MULTIBLOCK -> {
- if (this.placeMultiBlocks(this.stackToPlace)) return;
-
- setState(State.DONE);
- }
-
- case DONE -> {
- if(!workDone){
- workDone = true;
- BuildArea completedArea = builderEntity.getCurrentBuildArea();
-
- // Spawn any entities that were scanned with the structure (work areas, etc.)
- spawnScannedEntities(completedArea);
-
- completedArea.setBeingWorkedOn(false);
-
- //ONLY FOR BUILDING AREA WILL REMOVE IT
- this.builderEntity.getCurrentBuildArea().setDone(true);
- if (this.builderEntity.level() instanceof ServerLevel serverLevel) {
- BannerModSettlementRefreshSupport.refreshSnapshot(serverLevel, completedArea.blockPosition());
- }
-
- blockPos = null;
- builderEntity.setCurrentWorkArea(null);
- builderEntity.clearWorkStatus();
- this.start();
- }
- }
-
- case ERROR ->{
- if(!errorMessageDone){
- errorMessageDone = true;
- }
- }
- }
- }
-
- private boolean isBuildingAreaAvailable() {
- BuildArea area = builderEntity.getCurrentBuildArea();
- if(area == null || !area.isRemoved()) return true;
- else {
- builderEntity.setCurrentWorkArea(null);
- }
- return false;
- }
-
- public void setState(State state) {
- //if(builderEntity.getOwner() != null) builderEntity.getOwner().sendSystemMessage(Component.literal(state.toString()));
- this.state = state;
- }
-
- int blockBreakTime;
- public boolean mineBlocks(Stack positions){
- if(positions != null){
- if(blockPos == null){
- if(!positions.isEmpty()){
- blockPos = this.getNewMiningPosition(positions);
- }
- return blockPos != null;
- }
-
- BlockState state = builderEntity.getCommandSenderWorld().getBlockState(blockPos);
- if(state.isAir() || builderEntity.shouldIgnoreBlock(state)){
- if(!positions.isEmpty()){
- blockPos = this.getNewMiningPosition(positions);
- }
- else{
- this.blockPos = null;
- return false;
- }
- blockBreakTime = 0;
- }
- else{
- this.builderEntity.changeTool(state);
-
- this.builderEntity.mineBlock(blockPos);
- this.builderEntity.swing(InteractionHand.MAIN_HAND);
- }
- return true;
- }
- return false;
- }
-
- private BlockPos getNewMiningPosition(Stack positions) {
- positions.sort(Comparator.comparingDouble(
- pos -> builderEntity.position().distanceToSqr(pos.getCenter())
- ));
- positions.sort(Comparator.reverseOrder());
-
- BlockPos newPosition = null;
-
- if(blockPos == null){
- positions.removeIf(pos ->
- !canSeeBlock(builderEntity.getCommandSenderWorld(), builderEntity.position().add(0, 1, 0), pos)
- );
-
- if(positions.isEmpty()){
- setState(State.MOVE_TO_WORK_AREA);
- return null;
- }
-
- newPosition = positions.pop();
- }
- else if(positions.contains(blockPos.above())){
- newPosition = blockPos.above();
- }
- else if(positions.contains(blockPos.below())){
- newPosition = blockPos.below();
- }
- else{
- newPosition = positions.pop();
- }
- positions.remove(newPosition);
- return newPosition;
- }
- /**
- * Spawns work-area entities that were recorded during the structure scan.
- * Each entity is placed at the world position corresponding to its scanned relative offset,
- * rotated from scan-facing to build-facing, and inherits the owner UUID + team of the BuildArea.
- */
- private void spawnScannedEntities(BuildArea buildArea) {
- Level level = builderEntity.getCommandSenderWorld();
- if (!(level instanceof ServerLevel serverLevel)) return;
-
- CompoundTag nbt = buildArea.getStructureNBT();
- if (nbt == null || !nbt.contains("entities", Tag.TAG_LIST)) return;
-
- ListTag entityList = nbt.getList("entities", Tag.TAG_COMPOUND);
- if (entityList.isEmpty()) return;
-
- Direction scanFacing = Direction.byName(nbt.getString("facing"));
- Direction buildFacing = buildArea.getFacing();
- Direction buildRight = buildFacing.getClockWise();
- BlockPos origin = buildArea.getOriginPos();
- int width = buildArea.getWidthSize();
-
- if (scanFacing == null) scanFacing = Direction.SOUTH;
-
- // Rotation steps: from scan-facing to build-facing (same formula as block rotation)
- int rotSteps = ((buildFacing.get2DDataValue() - scanFacing.get2DDataValue()) % 4 + 4) % 4;
-
- for (Tag t : entityList) {
- CompoundTag entityTag = (CompoundTag) t;
- String typeId = entityTag.getString("entity_type");
- int relX = entityTag.getInt("x");
- int relY = entityTag.getInt("y");
- int relZ = entityTag.getInt("z");
- int scanFacingVal = entityTag.getInt("facing");
-
- // Look up entity type
- ResourceLocation rl = ResourceLocation.parse(typeId);
- EntityType> entityType = BuiltInRegistries.ENTITY_TYPE.getOptional(rl).orElse(null);
- if (entityType == null) continue;
-
- // Compute world position using same formula as setStartBuild / WorkerAreaRenderer
- BlockPos worldPos = origin
- .relative(buildFacing, relZ)
- .relative(buildRight, width - 1 - relX)
- .above(relY);
-
- // Create the entity
- Entity entity = entityType.create(serverLevel);
- if (entity == null) continue;
-
- entity.moveTo(worldPos.getX() + 0.5, worldPos.getY() + 1.0, worldPos.getZ() + 0.5, 0, 0);
-
- // Apply facing rotation: rotate the scanned facing by the same rotSteps
- if (entity instanceof AbstractWorkAreaEntity wa) {
- Direction entityFacing = Direction.from2DDataValue(scanFacingVal);
- Direction rotatedFacing = rotateDirection(entityFacing, rotSteps);
- wa.setFacing(rotatedFacing);
-
- // Restore stored dimensions, swapping width↔depth for 90° / 270° rotations
- if (entityTag.contains("wa_width")) {
- int waW = entityTag.getInt("wa_width");
- int waH = entityTag.getInt("wa_height");
- int waD = entityTag.getInt("wa_depth");
- if (rotSteps % 2 == 1) { int tmp = waW; waW = waD; waD = tmp; }
- wa.setWidthSize(waW);
- wa.setHeightSize(waH);
- wa.setDepthSize(waD);
- }
-
- // Transfer owner and team from the BuildArea
- if (buildArea.getPlayerUUID() != null) {
- wa.setPlayerUUID(buildArea.getPlayerUUID());
- }
- String team = buildArea.getTeamStringID();
- if (team != null && !team.isEmpty()) {
- wa.setTeamStringID(team);
- }
-
- wa.setCustomName(Component.literal(""));
- }
-
- serverLevel.addFreshEntity(entity);
- }
- }
-
- /** Rotates a horizontal Direction clockwise by the given number of 90° steps. */
- private static Direction rotateDirection(Direction dir, int steps) {
- steps = ((steps % 4) + 4) % 4;
- for (int i = 0; i < steps; i++) dir = dir.getClockWise();
- return dir;
- }
-
- public boolean placeBlocks(Stack positions){
- if(positions != null){
- if(blockPos == null){
- if(!positions.isEmpty()){
- blockPos = positions.pop();
- }
- else{
- return false;
- }
- }
-
- BlockState buildingState = builderEntity.getCurrentBuildArea().getStateFromPos(blockPos);
- BlockState levelState = builderEntity.getCommandSenderWorld().getBlockState(blockPos);
-
- if(builderEntity.getCurrentBuildArea().statesMatch(levelState, buildingState)){
- if(!positions.isEmpty()){
- blockPos = positions.pop();
- }
- else{
- return false;
- }
- }
- else if(buildingState != null) {
- if (!levelState.isAir() && !BuildArea.canDirectlyReplace(levelState, buildingState)) {
- this.builderEntity.changeTool(levelState);
- this.builderEntity.mineBlock(blockPos);
- this.builderEntity.swing(InteractionHand.MAIN_HAND);
- return true;
- }
-
- BuildBlockParse blockParse = BuildBlockParse.parseBlock(buildingState.getBlock());
- ItemStack buildingItem = builderEntity.getMatchingItem(itemStack -> itemStack.is(blockParse.getItem()));
- if(buildingItem != null){
- if(!builderEntity.getMainHandItem().is(buildingItem.getItem())){
- builderEntity.switchMainHandItem(itemStack -> itemStack.is(buildingItem.getItem()));
- }
- //CHECK IF IT WAS PARSED TO KEEP THE BLOCK-ROTATIONS OF NOT EFFECTED ONES
- if(blockParse.wasParsed() && buildingItem.getItem() instanceof BlockItem blockItem){
- buildingState = blockItem.getBlock().defaultBlockState();
- }
-
- BlockState secondaryState = builderEntity.getCurrentBuildArea().findPairedMultiBlockState(blockPos);
- if (secondaryState != null) {
- BlockPos secondaryPos = builderEntity.getCurrentBuildArea().findPairedMultiBlockPos(blockPos);
- builderEntity.getCommandSenderWorld().setBlock(blockPos, buildingState, Block.UPDATE_CLIENTS);
- builderEntity.getCommandSenderWorld().setBlock(secondaryPos, secondaryState, Block.UPDATE_ALL);
- builderEntity.getCommandSenderWorld().blockUpdated(blockPos, buildingState.getBlock());
- builderEntity.getCurrentBuildArea().removeMultiBlockToPlace(secondaryPos);
- } else {
- builderEntity.getCommandSenderWorld().setBlockAndUpdate(blockPos, buildingState);
- }
-
- builderEntity.getCommandSenderWorld().playSound(null, blockPos.getX(), blockPos.getY(), blockPos.getZ(), buildingState.getSoundType().getPlaceSound(), SoundSource.BLOCKS, 1.0F, 1.0F);
- this.builderEntity.swing(InteractionHand.MAIN_HAND);
- buildingItem.shrink(1);
- builderEntity.getCurrentBuildArea().removeBuildBlockToPlace(blockPos);
- }
- else{
- return false;
- }
- }
- return true;
- }
- this.blockPos = null;
- return false;
- }
-
-
- public boolean placeMultiBlocks(Stack positions) {
- if (positions == null || positions.isEmpty()) {
- this.blockPos = null;
- return false;
- }
-
- if (blockPos == null) {
- blockPos = positions.pop();
- }
-
- BlockState buildingState = builderEntity.getCurrentBuildArea().getStateFromMultiBlockPos(blockPos);
- if (buildingState != null) {
- BlockState levelState = builderEntity.getCommandSenderWorld().getBlockState(blockPos);
- if (!levelState.equals(buildingState)) {
- builderEntity.getCommandSenderWorld().setBlockAndUpdate(blockPos, buildingState);
- builderEntity.getCommandSenderWorld().playSound(null, blockPos.getX(), blockPos.getY(), blockPos.getZ(),
- buildingState.getSoundType().getPlaceSound(), SoundSource.BLOCKS, 1.0F, 1.0F);
- builderEntity.swing(InteractionHand.MAIN_HAND);
- }
- builderEntity.getCurrentBuildArea().removeMultiBlockToPlace(blockPos);
- }
-
- if (!positions.isEmpty()) {
- blockPos = positions.pop();
- return true;
- }
-
- blockPos = null;
- return false;
- }
-
- //PERFORMANCE HEAVY DO NOT USE FREQUENTLY
- private boolean canSeeBlock(Level level, Vec3 start, BlockPos target) {
- Vec3 targetCenter = target.getCenter();
- ClipContext ctx = new ClipContext(start, targetCenter, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, builderEntity);
- BlockPos ctxPos = level.clip(ctx).getBlockPos();
- return ctxPos.equals(target);
- }
-
- @Override
- public boolean canContinueToUse() {
- return canUse();
- }
-
- @Override
- public boolean isInterruptable() {
- return true;
- }
-
- @Override
- public boolean requiresUpdateEveryTick() {
- return true;
- }
-
- public static List getAvailableWorkAreasByPriority(ServerLevel level, BuilderEntity builderEntity, @Nullable BuildArea currentArea) {
- List list = com.talhanation.bannermod.entity.civilian.workarea.WorkAreaIndex.instance()
- .queryInRange(builderEntity, 64, BuildArea.class);
-
- Map priorityMap = new HashMap<>();
-
- for (BuildArea area : list) {
- if (area == null || area == currentArea || !area.canWorkHere(builderEntity)) continue;
-
- if(!area.hasPendingBuildWork()) continue;
-
- int priority = 0;
-
- boolean perfectCandidate = true;//area.isWorkerPerfectCandidate(builderEntity);
-
- if (perfectCandidate) {
- priority += 10;
- } else {
- priority += 1;
- }
-
- if (!area.isBeingWorkedOn()) {
- priority += 3;
- }
-
- priority += area.time;
- priority += WorkerBindingResume.priorityBoost(builderEntity.getBoundWorkAreaUUID(), area.getUUID());
-
- //double dist = area.position().distanceToSqr(builderEntity.position());
- //priority -= dist / 10.0;
-
- priorityMap.put(area, priority);
- }
-
-
- List sorted = new ArrayList<>(priorityMap.keySet());
- sorted.sort((a, b) -> Integer.compare(priorityMap.get(b), priorityMap.get(a)));
-
- return sorted;
- }
-
-
-
- public boolean moveToPosition(BlockPos pos, int threshold){
- if(pos == null){
- return false;
- }
- else{
- double distance = builderEntity.getHorizontalDistanceTo(pos.getCenter());
- if(distance < threshold){
- builderEntity.getNavigation().stop();
- lastPathRequestPos = null;
- return false;
- }
- else{
-
- builderEntity.setFollowState(6); //Working
- if(shouldRequestPath(pos)){
- builderEntity.getNavigation().moveTo(pos.getX(), pos.getY(), pos.getZ(), 0.8F);
- }
- builderEntity.getLookControl().setLookAt(pos.getCenter());
- }
- return true;
- }
- }
-
- private boolean shouldRequestPath(BlockPos pos) {
- if(!pos.equals(lastPathRequestPos) || builderEntity.tickCount - lastPathRequestTick >= PATH_REQUEST_COOLDOWN_TICKS){
- lastPathRequestPos = pos;
- lastPathRequestTick = builderEntity.tickCount;
- return true;
- }
- return false;
- }
-
- public enum State{
- SELECT_WORK_AREA,
- MOVE_TO_WORK_AREA,
- PREPARE_BREAK_BLOCKS,
- BREAK_BLOCKS,
- PREPARE_PLACE_BLOCKS,
- PLACE_BLOCKS,
- PREPARE_PLACE_MULTIBLOCK,
- PLACE_MULTIBLOCK,
- DONE,
- ERROR
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/ai/civilian/FarmerWorkGoal.java b/src/main/java/com/talhanation/bannermod/ai/civilian/FarmerWorkGoal.java
deleted file mode 100644
index 3d1f98ae..00000000
--- a/src/main/java/com/talhanation/bannermod/ai/civilian/FarmerWorkGoal.java
+++ /dev/null
@@ -1,498 +0,0 @@
-package com.talhanation.bannermod.ai.civilian;
-
-import com.talhanation.bannermod.entity.civilian.AbstractWorkerEntity;
-import com.talhanation.bannermod.entity.civilian.FarmerEntity;
-import com.talhanation.bannermod.entity.civilian.WorkerBindingResume;
-import com.talhanation.bannermod.entity.civilian.workarea.CropArea;
-import com.talhanation.bannermod.persistence.civilian.NeededItem;
-import net.minecraft.core.BlockPos;
-import net.minecraft.core.Direction;
-import net.minecraft.network.chat.Component;
-import net.minecraft.server.level.ServerLevel;
-import net.minecraft.sounds.SoundEvents;
-import net.minecraft.sounds.SoundSource;
-import net.minecraft.world.InteractionHand;
-import net.minecraft.world.entity.ai.goal.Goal;
-import net.minecraft.world.item.*;
-import net.minecraft.world.level.block.*;
-import net.minecraft.world.level.block.state.BlockState;
-import net.neoforged.neoforge.common.SpecialPlantable;
-
-import javax.annotation.Nullable;
-import java.util.*;
-
-public class FarmerWorkGoal extends Goal {
-
- private static final int PATH_REQUEST_COOLDOWN_TICKS = 20;
-
- public FarmerEntity farmer;
- public State state;
- public String errorMessage;
- public boolean errorMessageDone;
- public BlockPos blockPos;
- public Stack stackToPlant;
- public Stack stackToBreak;
- public Stack stackToPlow;
- public List neededItems = new ArrayList<>();
- private int lastPathRequestTick = -PATH_REQUEST_COOLDOWN_TICKS;
- @Nullable
- private BlockPos lastPathRequestPos;
- public FarmerWorkGoal(FarmerEntity farmer) {
- this.farmer = farmer;
- setFlags(EnumSet.of(Flag.LOOK, Flag.MOVE));
- }
-
- @Override
- public boolean canUse() {
- return !farmer.needsToSleep() && farmer.shouldWork() && !farmer.needsToGetToChest() && this.isCropAreaNotRemoved();
- }
-
- private boolean isCropAreaNotRemoved() {
- CropArea area = farmer.getCurrentCropArea();
- if(area == null || !area.isRemoved()) return true;
- else {
- farmer.setCurrentWorkArea(null);
- }
- return false;
- }
-
- @Override
- public void start() {
- super.start();
-
- setState(State.SELECT_WORK_AREA);
- }
- boolean workDone;
- int cooldown;
- @Override
- public void tick() {
- super.tick();
- if(this.farmer.getCommandSenderWorld().isClientSide()) return;
-
- if(state == null) return;
- if(blockPos != null) this.farmer.getLookControl().setLookAt(blockPos.getCenter());
- if(farmer.tickCount % 5 != 0) return;
-
- if(!isCropAreaNotRemoved()) return;
-
- if(state != State.SELECT_WORK_AREA && this.farmer.getCurrentCropArea() == null){
- setState(State.SELECT_WORK_AREA);
- return;
- }
-
- if(blockPos != null && moveToPosition(blockPos, 20)) return;
-
- switch(state){
- case SELECT_WORK_AREA -> {
- if(this.farmer.getCurrentCropArea() != null) {
- setState(State.MOVE_TO_WORK_AREA);
- return;
- }
-
- if(!FarmerAreaSelectionTiming.shouldSearchForArea(false, ++cooldown)) return;
- this.cooldown = 0;
-
- List areas = getAvailableWorkAreasByPriority((ServerLevel) farmer.getCommandSenderWorld(), farmer, this.farmer.getCurrentCropArea());
-
- if (!areas.isEmpty()) {
- this.farmer.setCurrentWorkArea(areas.get(0));
- }
-
- if(this.farmer.getCurrentCropArea() == null) {
- farmer.reportIdleReason("farmer_no_area", Component.literal(farmer.getName().getString() + ": Waiting for a crop area."));
- return;
- }
-
- farmer.clearWorkStatus();
- this.farmer.getCurrentCropArea().setBeingWorkedOn(true);
- this.farmer.getCurrentCropArea().setTime(0);
- this.workDone = false;
- setState(State.MOVE_TO_WORK_AREA);
- }
-
- case MOVE_TO_WORK_AREA ->{
- this.blockPos = null;
- if(this.moveToPosition(this.farmer.getCurrentCropArea().getOnPos(), 20)) return;
- setState(State.PREPARE_BREAK_BLOCKS);
- }
- case PREPARE_BREAK_BLOCKS -> {
- this.farmer.getCurrentCropArea().scanBreakArea();
-
- this.stackToBreak = this.farmer.getCurrentCropArea().stackToBreak;
-
- if(stackToBreak.isEmpty()){
- setState(State.PREPARE_PLOWING);
- return;
- }
-
- farmer.switchMainHandItem(itemStack -> itemStack.getItem().getDefaultInstance().isEmpty());
-
- setState(State.BREAK_BLOCKS);
- }
- case BREAK_BLOCKS -> {
- if(this.breakBlocks(this.stackToBreak)) return;
-
- setState(State.PREPARE_WATER_SPOT);
- }
- case PREPARE_WATER_SPOT -> {
- BlockState centerPosState = farmer.getCommandSenderWorld().getBlockState(this.farmer.getCurrentCropArea().getWaterPosCenter());
- if(centerPosState.isAir()){
-
- ItemStack itemStack = farmer.getMatchingItem(item -> farmer.isBucketWithWater(item));
- if(itemStack == null){
- farmer.requestRequiredItem(new NeededItem(item -> farmer.isBucketWithWater(item), 1, true),
- "farmer_missing_water_bucket",
- Component.literal(farmer.getName().getString() + ": I need a water bucket to prepare this field."));
- return;
- }
- else if(itemStack.getItem() instanceof BucketItem bucketItem){
- farmer.switchMainHandItem(item -> farmer.isBucketWithWater(item));
-
- bucketItem.emptyContents(null, farmer.getCommandSenderWorld(), this.farmer.getCurrentCropArea().getWaterPosCenter(), null);
- }
- }
-
- setState(State.PREPARE_PLOWING);
- }
-
- case PREPARE_PLOWING -> {
- this.farmer.getCurrentCropArea().scanPlowArea();
-
- this.stackToPlow = this.farmer.getCurrentCropArea().stackToPlow;
- if(stackToPlow.isEmpty()){
- applyLoopDecision(FarmerLoopProgress.selectNextAction(false, false, true));
- return;
- }
-
- farmer.switchMainHandItem(itemStack -> itemStack.getItem() instanceof HoeItem);
-
- boolean hasHoe = farmer.getMainHandItem().getItem() instanceof HoeItem;
- if(!hasHoe){
- farmer.requestRequiredItem(new NeededItem(stack -> stack.getItem() instanceof HoeItem, 1, true),
- "farmer_missing_hoe",
- Component.literal(farmer.getName().getString() + ": I need a hoe to keep working."));
- this.blockPos = null;
- applyLoopDecision(FarmerLoopProgress.waitForRequiredItem(FarmerLoopProgress.Action.PREPARE_PLOWING));
- return;
- }
-
- setState(State.PLOWING);
- }
- case PLOWING -> {
- if(this.plowBlocks(stackToPlow)) return;
-
- setState(State.PREPARE_PLANT_SEEDS);
- }
-
- case PREPARE_PLANT_SEEDS -> {
- this.farmer.getCurrentCropArea().scanPlantArea();
-
- this.stackToPlant = this.farmer.getCurrentCropArea().stackToPlant;
- if(stackToPlant.isEmpty()){
- applyLoopDecision(FarmerLoopProgress.selectNextAction(false, false, false));
- return;
- }
-
- ItemStack seedTemplate = FarmerPlantingPreparation.resolveSeedTemplate(this.farmer.getCurrentCropArea().getSeedStack(), this.farmer.getInventory());
- if(!seedTemplate.isEmpty() && this.farmer.getCurrentCropArea().getSeedStack().isEmpty()){
- this.farmer.getCurrentCropArea().setSeedStack(seedTemplate);
- this.farmer.getCurrentCropArea().updateType();
- }
-
- if(this.farmer.getCurrentCropArea().getSeedStack().isEmpty()){
- farmer.requestRequiredItem(new NeededItem(FarmerPlantingPreparation::isSupportedSeed, stackToPlant.size(), true),
- "farmer_missing_seeds",
- Component.literal(farmer.getName().getString() + ": I need seeds for this field."));
- this.blockPos = null;
- applyLoopDecision(FarmerLoopProgress.waitForRequiredItem(FarmerLoopProgress.Action.PREPARE_PLANT_SEEDS));
- return;
- }
-
- ItemStack seedFromInv = farmer.getMatchingItem(itemStack -> ItemStack.isSameItemSameComponents(itemStack, this.farmer.getCurrentCropArea().getSeedStack()));
- if(seedFromInv == null){
- ItemStack seedStack = this.farmer.getCurrentCropArea().getSeedStack();
- farmer.requestRequiredItem(new NeededItem(itemStack -> ItemStack.isSameItemSameComponents(itemStack, seedStack), stackToPlant.size(), true),
- "farmer_missing_seeds",
- Component.literal(farmer.getName().getString() + ": I need more seeds for this field."));
- this.blockPos = null;
- applyLoopDecision(FarmerLoopProgress.waitForRequiredItem(FarmerLoopProgress.Action.PREPARE_PLANT_SEEDS));
- return;
- }
-
- farmer.clearWorkStatus();
- this.farmer.switchMainHandItem(itemStack -> itemStack.is(this.farmer.getCurrentCropArea().getSeedStack().getItem()));
-
- setState(State.PLANT_SEEDS);
- }
-
- case PLANT_SEEDS -> {
- if(this.plantSeeds(stackToPlant)) return;
-
- setState(State.DONE);
- }
-
- case DONE -> {
- if(!workDone){
- workDone = true;
- setState(State.SELECT_WORK_AREA);
-
- this.farmer.getCurrentCropArea().setBeingWorkedOn(false);
- blockPos = null;
- this.farmer.setCurrentWorkArea(null);
- this.cooldown = FarmerAreaSelectionTiming.cooldownAfterWorkCycle();
-
- if(!this.neededItems.isEmpty()){
- for(NeededItem neededItem : neededItems){
- this.farmer.addNeededItem(neededItem);
- }
- this.neededItems.clear();
- }
- else {
- farmer.clearWorkStatus();
- }
- }
- }
-
- case ERROR ->{
- if(!errorMessageDone){
- errorMessageDone = true;
- }
- }
- }
- }
-
- public void setState(State state) {
- //if(farmer.getOwner() != null) farmer.getOwner().sendSystemMessage(Component.literal(state.toString()));
- this.state = state;
- }
-
- private void applyLoopDecision(FarmerLoopProgress.Decision decision) {
- if (decision == null) {
- return;
- }
-
- switch (decision.action()) {
- case PREPARE_BREAK_BLOCKS -> setState(State.PREPARE_BREAK_BLOCKS);
- case PREPARE_PLOWING -> setState(State.PREPARE_PLOWING);
- case PREPARE_PLANT_SEEDS -> setState(State.PREPARE_PLANT_SEEDS);
- case WAIT_FOR_ITEM -> setState(mapActionToState(decision.resumeAction()));
- case FINISHED -> setState(State.DONE);
- }
- }
-
- private State mapActionToState(FarmerLoopProgress.Action action) {
- return switch (action) {
- case PREPARE_BREAK_BLOCKS -> State.PREPARE_BREAK_BLOCKS;
- case PREPARE_PLOWING -> State.PREPARE_PLOWING;
- case PREPARE_PLANT_SEEDS -> State.PREPARE_PLANT_SEEDS;
- case WAIT_FOR_ITEM, FINISHED -> state;
- };
- }
-
- @Override
- public boolean canContinueToUse() {
- return canUse();
- }
-
- @Override
- public boolean isInterruptable() {
- return true;
- }
-
- @Override
- public boolean requiresUpdateEveryTick() {
- return true;
- }
-
- public boolean plantSeeds(Stack positions){
- if(positions != null){
- ItemStack seedFromInv = farmer.getMatchingItem(itemStack -> itemStack.is(this.farmer.getCurrentCropArea().getSeedStack().getItem()));
- if(seedFromInv == null){
- seedFromInv = farmer.getMatchingItem(itemStack -> ItemStack.isSameItemSameComponents(itemStack, this.farmer.getCurrentCropArea().getSeedStack()));
- }
- if(seedFromInv == null){
- setState(State.PREPARE_PLANT_SEEDS);
- return false;
- }
-
- if(blockPos == null){
- if(!positions.isEmpty()) blockPos = positions.pop();
- return blockPos != null;
- }
-
- BlockState state = farmer.getCommandSenderWorld().getBlockState(blockPos);
- if(state.getBlock() instanceof CropBlock || state.getBlock() instanceof StemBlock){
- if(!positions.isEmpty()){
- blockPos = positions.pop();
- }
- else{
- this.blockPos = null;
- return false;
- }
- }
- else if (seedFromInv.getItem() instanceof BlockItem blockItem) {
- farmer.getCommandSenderWorld().setBlockAndUpdate(blockPos, blockItem.getBlock().defaultBlockState());
-
- farmer.getCommandSenderWorld().playSound(null, blockPos.getX(), blockPos.getY(), blockPos.getZ(), SoundEvents.CROP_PLANTED, SoundSource.BLOCKS, 1.0F, 1.0F);
- seedFromInv.shrink(1);
- this.farmer.swing(InteractionHand.MAIN_HAND);
- }
- else if (seedFromInv.getItem() instanceof SpecialPlantable plantable) {
- if (plantable.canPlacePlantAtPosition(seedFromInv, farmer.getCommandSenderWorld(), blockPos, Direction.UP)) {
- plantable.spawnPlantAtPosition(seedFromInv, farmer.getCommandSenderWorld(), blockPos, Direction.UP);
-
- farmer.getCommandSenderWorld().playSound(null, blockPos.getX(), blockPos.getY(), blockPos.getZ(), SoundEvents.CROP_PLANTED, SoundSource.BLOCKS, 1.0F, 1.0F);
- seedFromInv.shrink(1);
- this.farmer.swing(InteractionHand.MAIN_HAND);
- }
- }
- return true;
- }
- this.blockPos = null;
- return false;
- }
-
- public boolean plowBlocks(Stack positions){
- if(positions != null){
- boolean hasTool = farmer.getMainHandItem().getItem() instanceof HoeItem;
- if(!hasTool){
- setState(State.PREPARE_PLOWING);
- return true;
- }
-
- if(blockPos == null){
- if(!positions.isEmpty()) blockPos = positions.pop();
- return blockPos != null;
- }
-
- BlockState state = farmer.getCommandSenderWorld().getBlockState(blockPos);
- if(state.getBlock() instanceof FarmBlock){
- if(!positions.isEmpty()){
- blockPos = positions.pop();
- }
- else{
- this.blockPos = null;
- return false;
- }
- }
- else{
- this.farmer.swing(InteractionHand.MAIN_HAND);
- farmer.getCommandSenderWorld().setBlock(blockPos, Blocks.FARMLAND.defaultBlockState(), 3);
- farmer.getCommandSenderWorld().playSound(null, blockPos.getX(), blockPos.getY(), blockPos.getZ(), SoundEvents.HOE_TILL, SoundSource.BLOCKS, 1.0F, 1.0F);
- this.farmer.damageMainHandItem();
- }
- return true;
- }
- return false;
- }
- int blockBreakTime;
- public boolean breakBlocks(Stack positions){
- if(positions != null){
- if(blockPos == null){
- if(!positions.isEmpty()) blockPos = positions.pop();
- return blockPos != null;
- }
-
- if(AbstractWorkerEntity.isPosBroken(blockPos, this.farmer.getCommandSenderWorld(), true)){
- if(!positions.isEmpty()){
- blockPos = positions.pop();
- }
- else{
- this.blockPos = null;
- return false;
- }
- blockBreakTime = 0;
-
- }
- else{
- this.farmer.mineBlock(blockPos);
- this.farmer.swing(InteractionHand.MAIN_HAND);
- }
- return true;
- }
- return false;
- }
-
- public static List getAvailableWorkAreasByPriority(ServerLevel level, FarmerEntity farmer, @Nullable CropArea currentArea) {
- List list = com.talhanation.bannermod.entity.civilian.workarea.WorkAreaIndex.instance()
- .queryInRange(farmer, 64, CropArea.class);
-
- Map priorityMap = new HashMap<>();
-
- for (CropArea area : list) {
- if (area == null || area == currentArea || !area.canWorkHere(farmer)) continue;
-
- int priority = 0;
-
- boolean perfectCandidate = area.isWorkerPerfectCandidate(farmer);
-
- if (perfectCandidate) {
- priority += 10;
- } else {
- priority += 1;
- }
-
- if (!area.isBeingWorkedOn()) {
- priority += 10;
- }
-
- priority += area.getTime() * 10;
- priority += WorkerBindingResume.priorityBoost(farmer.getBoundWorkAreaUUID(), area.getUUID());
-
- priorityMap.put(area, priority);
- }
-
- List sorted = new ArrayList<>(priorityMap.keySet());
- sorted.sort((a, b) -> Integer.compare(priorityMap.get(b), priorityMap.get(a)));
-
- return sorted;
- }
-
-
-
- public boolean moveToPosition(BlockPos pos, int threshold){
- if(pos == null){
- return false;
- }
- else{
- double distance = farmer.getHorizontalDistanceTo(pos.getCenter());
- if(distance < threshold){
- farmer.getNavigation().stop();
- lastPathRequestPos = null;
- return false;
- }
- else{
- if(shouldRequestPath(pos) || farmer.getNavigation().isDone()){
- farmer.getNavigation().moveTo(pos.getX() + 0.5D, pos.getY(), pos.getZ() + 0.5D, 0.8F);
- }
- farmer.setFollowState(6); //Working
- farmer.getLookControl().setLookAt(pos.getCenter());
- }
- return true;
- }
- }
-
- private boolean shouldRequestPath(BlockPos pos) {
- if(!pos.equals(lastPathRequestPos) || farmer.tickCount - lastPathRequestTick >= PATH_REQUEST_COOLDOWN_TICKS){
- lastPathRequestPos = pos;
- lastPathRequestTick = farmer.tickCount;
- return true;
- }
- return false;
- }
-
- public enum State{
- SELECT_WORK_AREA,
- MOVE_TO_WORK_AREA,
- PREPARE_BREAK_BLOCKS,
- BREAK_BLOCKS,
- PREPARE_WATER_SPOT,
- PREPARE_PLOWING,
- PLOWING,
- PREPARE_PLANT_SEEDS,
- PLANT_SEEDS,
- DONE,
- ERROR
-
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/ai/civilian/FishermanWorkGoal.java b/src/main/java/com/talhanation/bannermod/ai/civilian/FishermanWorkGoal.java
deleted file mode 100644
index 4f9062d2..00000000
--- a/src/main/java/com/talhanation/bannermod/ai/civilian/FishermanWorkGoal.java
+++ /dev/null
@@ -1,313 +0,0 @@
-package com.talhanation.bannermod.ai.civilian;
-
-import com.talhanation.bannermod.entity.civilian.FishermanEntity;
-import com.talhanation.bannermod.entity.civilian.WorkerBindingResume;
-import com.talhanation.bannermod.entity.civilian.FishingBobberEntity;
-import com.talhanation.bannermod.entity.civilian.workarea.FishingArea;
-import com.talhanation.bannermod.persistence.civilian.NeededItem;
-import net.minecraft.core.BlockPos;
-import net.minecraft.network.chat.Component;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.level.ServerLevel;
-import net.minecraft.sounds.SoundEvents;
-import net.minecraft.world.InteractionHand;
-import net.minecraft.world.entity.ai.goal.Goal;
-import net.minecraft.world.item.FishingRodItem;
-import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.item.enchantment.EnchantmentHelper;
-import net.minecraft.world.level.storage.loot.BuiltInLootTables;
-import net.minecraft.world.level.storage.loot.LootParams;
-import net.minecraft.world.level.storage.loot.LootTable;
-import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
-import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
-import net.minecraft.world.phys.Vec3;
-
-import javax.annotation.Nullable;
-import java.util.*;
-
-public class FishermanWorkGoal extends Goal {
-
- private static final int PATH_REQUEST_COOLDOWN_TICKS = 20;
-
- public FishermanEntity fisherman;
- public FishingBobberEntity fishingBobber;
- public State state;
- public String errorMessage;
- public boolean errorMessageDone;
- public BlockPos blockPos;
- private int catchTime = 0;
- private int throwTime;
- private int lastPathRequestTick = -PATH_REQUEST_COOLDOWN_TICKS;
- @Nullable
- private BlockPos lastPathRequestPos;
- public FishermanWorkGoal(FishermanEntity fisherman) {
- this.fisherman = fisherman;
- setFlags(EnumSet.of(Flag.LOOK, Flag.MOVE));
- }
-
- @Override
- public boolean canUse() {
- return !fisherman.needsToSleep() && fisherman.shouldWork() && !fisherman.needsToGetToChest() && this.isAreaNotRemoved();
- }
-
- private boolean isAreaNotRemoved() {
- FishingArea area = fisherman.getCurrentFishingArea();
- if(area == null || !area.isRemoved()) return true;
- else {
- fisherman.setCurrentWorkArea(null);
- }
- return false;
- }
-
- @Override
- public void start() {
- super.start();
- setState(State.SELECT_WORK_AREA);
- }
-
- @Override
- public void stop() {
- super.stop();
- if(fishingBobber != null && fishingBobber.isAlive()){
- this.fisherman.playSound(SoundEvents.FISHING_BOBBER_SPLASH, 1, 1);
- this.fishingBobber.discard();
- this.fishingBobber = null;
- }
- }
-
- int cooldown;
- @Override
- public void tick() {
- super.tick();
- if(this.fisherman.getCommandSenderWorld().isClientSide()) return;
- if(state == null) return;
- if(blockPos != null) this.fisherman.getLookControl().setLookAt(blockPos.getCenter());
- if(fisherman.tickCount % 5 != 0) return;
-
- if(!isAreaNotRemoved()) return;
-
- if(state != State.SELECT_WORK_AREA && this.fisherman.getCurrentFishingArea() == null){
- setState(State.SELECT_WORK_AREA);
- return;
- }
-
- switch(state){
- case SELECT_WORK_AREA -> {
- if(this.fisherman.getCurrentFishingArea() != null) setState(State.MOVE_TO_WORK_AREA);
-
- if(++cooldown < fisherman.getRandom().nextInt(300)) return;
- this.cooldown = 0;
-
- List areas = getAvailableWorkAreasByPriority((ServerLevel) fisherman.getCommandSenderWorld(), fisherman, this.fisherman.getCurrentFishingArea());
-
- if (!areas.isEmpty()) {
- this.fisherman.setCurrentWorkArea(areas.get(0));
- }
-
- if(this.fisherman.getCurrentFishingArea() == null) {
- fisherman.reportIdleReason("fisherman_no_area", Component.literal(fisherman.getName().getString() + ": Waiting for a fishing area."));
- return;
- }
-
- fisherman.clearWorkStatus();
- this.fisherman.getCurrentFishingArea().setBeingWorkedOn(true);
- this.fisherman.getCurrentFishingArea().setTime(0);
-
- setState(State.MOVE_TO_WORK_AREA);
- }
-
- case MOVE_TO_WORK_AREA -> {
- this.blockPos = null;
- if(this.moveToPosition(this.fisherman.getCurrentFishingArea().getOnPos(), 20)) return;
-
- setState(State.PREPARE_FISHING);
- }
-
- case PREPARE_FISHING -> {
- if(++cooldown < 20) return;
- this.cooldown = 0;
-
- if(!fisherman.hasFreeInvSlot()){
- fisherman.reportBlockedReason("fisherman_inventory_full", Component.literal(fisherman.getName().getString() + ": My inventory is full."));
- fisherman.forcedDeposit = true;
- return;
- }
-
- boolean hasFishingRod = fisherman.getInventory().hasAnyMatching(itemStack -> itemStack.getItem() instanceof FishingRodItem);
- if(!hasFishingRod){
- fisherman.requestRequiredItem(new NeededItem(stack -> stack.getItem() instanceof FishingRodItem, 1, true),
- "fisherman_missing_rod",
- Component.literal(fisherman.getName().getString() + ": I need a fishing rod to continue."));
- return;
- }
- else {
- fisherman.clearWorkStatus();
- fisherman.switchMainHandItem(itemStack -> itemStack.getItem() instanceof FishingRodItem);
- }
-
- this.fisherman.swing(InteractionHand.MAIN_HAND);
- this.fisherman.playSound(SoundEvents.FISHING_BOBBER_THROW, 1, 1);
-
- Vec3 center = fisherman.getCurrentFishingArea().getArea().getCenter();
-
- this.fishingBobber = fisherman.throwFishingHook(center);
-
- blockPos = BlockPos.containing(center);
-
- catchTime = 130;
-
- setState(State.FISHING);
- }
-
- case FISHING -> {
- if(fishingBobber != null){
- if(fishingBobber.hooked){
- setState(State.CATCH);
- return;
- }
- else if(fishingBobber.onGround()){
- this.fisherman.swing(InteractionHand.MAIN_HAND);
- this.fisherman.playSound(SoundEvents.FISHING_BOBBER_RETRIEVE, 1, 1);
- this.fishingBobber.discard();
- this.fishingBobber = null;
-
- setState(State.MOVE_TO_WORK_AREA);
- return;
- }
- }
-
- if(++throwTime > catchTime){
- throwTime = 0;
- this.fisherman.playSound(SoundEvents.FISHING_BOBBER_SPLASH, 1, 1);
- setState(State.CATCH);
- }
- }
-
- case CATCH -> {
- this.fisherman.swing(InteractionHand.MAIN_HAND);
- this.fisherman.playSound(SoundEvents.FISHING_BOBBER_RETRIEVE, 1, 1);
-
- this.spawnFishingLoot();
-
- if(this.fishingBobber != null){
- this.fishingBobber.discard();
- this.fishingBobber = null;
- }
- this.fisherman.farmedItems++;
- if(this.fisherman.tickCount % 2 == 0) this.fisherman.damageMainHandItem();
-
- setState(State.PREPARE_FISHING);
- }
-
- case DONE -> {
- this.fisherman.getCurrentFishingArea().setBeingWorkedOn(false);
- blockPos = null;
- this.fisherman.setCurrentWorkArea(null);
- fisherman.clearWorkStatus();
- }
-
- case ERROR -> {
- if(!errorMessageDone){
- errorMessageDone = true;
- }
- }
- }
- }
-
- public void setState(State state) {
- //if(fisherman.getOwner() != null) fisherman.getOwner().sendSystemMessage(Component.literal(state.toString()));
- this.state = state;
- }
-
- @Override
- public boolean canContinueToUse() {
- return canUse();
- }
-
- @Override
- public boolean isInterruptable() {
- return true;
- }
-
- @Override
- public boolean requiresUpdateEveryTick() {
- return true;
- }
-
- public static List getAvailableWorkAreasByPriority(ServerLevel level, FishermanEntity fisherman, @Nullable FishingArea currentArea) {
- List list = com.talhanation.bannermod.entity.civilian.workarea.WorkAreaIndex.instance()
- .queryInRange(fisherman, 64, FishingArea.class);
-
- WorkerBindingResume.prioritizeBoundFirst(list, fisherman.getBoundWorkAreaUUID(), FishingArea::getUUID);
-
-
- return list;
- }
-
- public boolean moveToPosition(BlockPos pos, int threshold){
- if(pos == null){
- return false;
- }
- else{
- double distance = fisherman.getHorizontalDistanceTo(pos.getCenter());
- if(distance < threshold){
- fisherman.getNavigation().stop();
- lastPathRequestPos = null;
- return false;
- }
- else{
- if(shouldRequestPath(pos)){
- fisherman.getNavigation().moveTo(pos.getX(), pos.getY(), pos.getZ(), 0.8F);
- }
- fisherman.setFollowState(6); //Working
- fisherman.getLookControl().setLookAt(pos.getCenter());
- }
- return true;
- }
- }
-
- private boolean shouldRequestPath(BlockPos pos) {
- if(!pos.equals(lastPathRequestPos) || fisherman.tickCount - lastPathRequestTick >= PATH_REQUEST_COOLDOWN_TICKS){
- lastPathRequestPos = pos;
- lastPathRequestTick = fisherman.tickCount;
- return true;
- }
- return false;
- }
-
- public void spawnFishingLoot() {
- if(fishingBobber == null ) return;
-
- ServerLevel serverLevel = (ServerLevel)this.fisherman.getCommandSenderWorld();
- double luckFromTool = EnchantmentHelper.getFishingLuckBonus(serverLevel, this.fisherman.getItemInHand(InteractionHand.MAIN_HAND), this.fisherman);
- double luckFromDepth = Math.min(25, fishingBobber.getWaterDepth())/10F;
- double luck = 0.1D + luckFromTool + luckFromDepth;
-
- LootParams lootparams = (new LootParams.Builder(serverLevel))
- .withParameter(LootContextParams.ORIGIN, this.fisherman.position())
- .withParameter(LootContextParams.TOOL, fisherman.getMainHandItem())
- .withParameter(LootContextParams.ATTACKING_ENTITY, this.fisherman)
- .withLuck((float)(luck + luckFromTool))
- .create(LootContextParamSets.FISHING);
- LootTable loottable = this.fisherman.getCommandSenderWorld().getServer().reloadableRegistries().getLootTable(BuiltInLootTables.FISHING);
- List list = loottable.getRandomItems(lootparams);
-
- MinecraftServer server = fisherman.getServer();
- if (server == null) return;
-
- for (ItemStack itemstack : list) {
- fisherman.getInventory().addItem(itemstack);
- }
- }
-
- public enum State{
- SELECT_WORK_AREA,
- MOVE_TO_WORK_AREA,
- PREPARE_FISHING,
- FISHING,
- CATCH,
- DONE,
- ERROR
-
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/ai/civilian/LumberjackWorkGoal.java b/src/main/java/com/talhanation/bannermod/ai/civilian/LumberjackWorkGoal.java
deleted file mode 100644
index f26a924a..00000000
--- a/src/main/java/com/talhanation/bannermod/ai/civilian/LumberjackWorkGoal.java
+++ /dev/null
@@ -1,499 +0,0 @@
-package com.talhanation.bannermod.ai.civilian;
-
-import com.talhanation.bannermod.entity.civilian.LumberjackEntity;
-import com.talhanation.bannermod.entity.civilian.WorkerBindingResume;
-import com.talhanation.bannermod.entity.civilian.workarea.LumberArea;
-import com.talhanation.bannermod.persistence.civilian.NeededItem;
-import com.talhanation.bannermod.persistence.civilian.Tree;
-import net.minecraft.core.BlockPos;
-import net.minecraft.network.chat.Component;
-import net.minecraft.server.level.ServerLevel;
-import net.minecraft.sounds.SoundEvents;
-import net.minecraft.sounds.SoundSource;
-import net.minecraft.world.InteractionHand;
-import net.minecraft.world.entity.ai.goal.Goal;
-import net.minecraft.world.item.AxeItem;
-import net.minecraft.world.item.BlockItem;
-import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.item.ShearsItem;
-import net.minecraft.world.level.block.Block;
-import net.minecraft.world.level.block.Blocks;
-import net.minecraft.world.level.block.SaplingBlock;
-import net.minecraft.world.level.block.state.BlockState;
-
-import javax.annotation.Nullable;
-import java.util.*;
-
-public class LumberjackWorkGoal extends Goal {
-
- private static final int AREA_SEARCH_COOLDOWN_TICKS = 20;
- private static final int PATH_REQUEST_COOLDOWN_TICKS = 20;
-
- public LumberjackEntity lumberjack;
- public State state;
- public String errorMessage;
- public boolean errorMessageDone;
- public BlockPos blockPos;
- public Stack stackOfTrees;
- public Stack stackToPlant;
- public Tree currentTree;
- private int lastAreaSearchTick = -AREA_SEARCH_COOLDOWN_TICKS;
- private int lastPathRequestTick = -PATH_REQUEST_COOLDOWN_TICKS;
- @Nullable
- private BlockPos lastPathRequestPos;
-
- public LumberjackWorkGoal(LumberjackEntity lumberjack) {
- this.lumberjack = lumberjack;
- setFlags(EnumSet.of(Flag.LOOK, Flag.MOVE));
- }
-
- @Override
- public boolean canUse() {
- return !lumberjack.needsToSleep() && lumberjack.shouldWork() && !lumberjack.needsToGetToChest();
- }
-
- @Override
- public void start() {
- super.start();
- if(this.lumberjack.getCommandSenderWorld().isClientSide()) return;
-
-
- setState(State.SELECT_WORK_AREA);
- }
- boolean workDone;
- @Override
- public void tick() {
- super.tick();
- if(this.lumberjack.getCommandSenderWorld().isClientSide()) return;
- if(state == null) return;
- if(blockPos != null) this.lumberjack.getLookControl().setLookAt(blockPos.getCenter());
-
- if(state == State.WOOD_CUTTING){
- if(this.breakBlocks(currentTree.getStackToBreak())) return;
-
- currentTree.setInWork(false);
- setState(State.SELECT_TREE);
- }
-
- if(lumberjack.tickCount % 10 != 0) return;
-
- switch(state){
- case SELECT_WORK_AREA ->{
- if(lumberjack.getCurrentLumberArea() != null) setState(State.MOVE_TO_WORK_AREA);
-
- if(lumberjack.tickCount - lastAreaSearchTick < AREA_SEARCH_COOLDOWN_TICKS) return;
- lastAreaSearchTick = lumberjack.tickCount;
-
- List areas = getAvailableWorkAreasByPriority((ServerLevel) lumberjack.getCommandSenderWorld(), lumberjack, lumberjack.getCurrentLumberArea());
-
- if (!areas.isEmpty()) {
- lumberjack.setCurrentWorkArea(areas.get(0));
- }
-
- if(lumberjack.getCurrentLumberArea() == null) {
- lumberjack.reportIdleReason("lumberjack_no_area", Component.literal(lumberjack.getName().getString() + ": Waiting for a lumber area."));
- return;
- }
-
- lumberjack.clearWorkStatus();
- lumberjack.getCurrentLumberArea().setBeingWorkedOn(true);
- this.lumberjack.getCurrentLumberArea().setTime(0);
- workDone = false;
- setState(State.MOVE_TO_WORK_AREA);
- }
-
- case MOVE_TO_WORK_AREA ->{
- this.blockPos = null;
- if(this.moveToPosition(lumberjack.getCurrentLumberArea().getOnPos(), 100)) return;
-
- setState(State.SCAN_TREES);
- }
-
- case SCAN_TREES ->{
- if(lumberjack.getCurrentLumberArea().stackOfTrees.isEmpty()){
- lumberjack.getCurrentLumberArea().scanForTrees();
- }
-
- this.stackOfTrees = lumberjack.getCurrentLumberArea().stackOfTrees;
- this.stackOfTrees.sort(Comparator.comparing(tree -> tree.getPosition().getCenter().distanceToSqr(lumberjack.position())));
-
- if(stackOfTrees.isEmpty()){
-
- setState(State.PREPARE_PLANT_SAPLINGS);
- return;
- }
-
- setState(State.SELECT_TREE);
- }
-
- case SELECT_TREE -> {
- if(stackOfTrees.isEmpty()){
- setState(State.SCAN_TREES);
- return;
- }
-
- this.currentTree = this.stackOfTrees.pop();
- this.currentTree.setInWork(true);
- setState(State.MOVE_TO_TREE);
- }
-
- case MOVE_TO_TREE -> {
- if(this.moveToPosition(currentTree.getPosition(), 30)) return;
-
- setState(State.PREPARE_SHEAR_LEAVES);
- }
- case PREPARE_SHEAR_LEAVES -> {
- if(!lumberjack.getCurrentLumberArea().getShearLeaves()){
- setState(State.PREPARE_STRIP_LOGS);
- return;
- }
- lumberjack.switchMainHandItem(itemStack -> itemStack.getItem() instanceof ShearsItem);
-
- boolean hasShears = lumberjack.getMainHandItem().getItem() instanceof ShearsItem;
- if(!hasShears){
- lumberjack.requestRequiredItem(new NeededItem(stack -> stack.getItem() instanceof ShearsItem, 1, true),
- "lumberjack_missing_shears",
- Component.literal(lumberjack.getName().getString() + ": I need shears to trim leaves."));
- this.blockPos = null;
- return;
- }
-
- setState(State.SHEAR_LEAVES);
- }
- case SHEAR_LEAVES -> {
- if(lumberjack.getCurrentLumberArea().getShearLeaves() && this.shearLeaves(currentTree.getStackToShear())) return;
-
- setState(State.PREPARE_STRIP_LOGS);
- }
- case PREPARE_STRIP_LOGS -> {
- if(!lumberjack.getCurrentLumberArea().getStripLogs()){
- setState(State.PREPARE_WOOD_CUTTING);
- return;
- }
-
- lumberjack.switchMainHandItem(itemStack -> itemStack.getItem() instanceof AxeItem);
-
- boolean hasAxe = lumberjack.getMainHandItem().getItem() instanceof AxeItem;
- if(!hasAxe){
- lumberjack.requestRequiredItem(new NeededItem(stack -> stack.getItem() instanceof AxeItem, 1, true),
- "lumberjack_missing_axe",
- Component.literal(lumberjack.getName().getString() + ": I need an axe to continue."));
- this.blockPos = null;
- return;
- }
-
- setState(State.STRIP_WOOD);
- }
- case STRIP_WOOD -> {
- if(lumberjack.getCurrentLumberArea().getStripLogs() && this.stripLogs(currentTree.getStackToStrip())) return;
-
- setState(State.PREPARE_WOOD_CUTTING);
- }
- case PREPARE_WOOD_CUTTING -> {
- lumberjack.switchMainHandItem(itemStack -> itemStack.getItem() instanceof AxeItem);
-
- boolean hasAxe = lumberjack.getMainHandItem().getItem() instanceof AxeItem;
- if(!hasAxe){
- lumberjack.requestRequiredItem(new NeededItem(stack -> stack.getItem() instanceof AxeItem, 1, true),
- "lumberjack_missing_axe",
- Component.literal(lumberjack.getName().getString() + ": I need an axe to continue."));
- this.blockPos = null;
- return;
- }
-
- setState(State.WOOD_CUTTING);
- }
- case WOOD_CUTTING -> {
-
- }
-
- case PREPARE_PLANT_SAPLINGS -> {
- if(!lumberjack.getCurrentLumberArea().getReplant()){
- setState(State.DONE);
- return;
- }
-
- this.lumberjack.getCurrentLumberArea().scanPlantArea();
- this.stackToPlant = lumberjack.getCurrentLumberArea().stackToPlant;
-
- if(stackToPlant.isEmpty()){
- setState(State.DONE);
- return;
- }
-
- setState(State.PLANT_SAPLINGS);
- }
-
- case PLANT_SAPLINGS -> {
- if(lumberjack.getCurrentLumberArea().getReplant() && this.plantSaplings(lumberjack.getCurrentLumberArea().getStackToPlant())) return;
-
- setState(State.DONE);
- }
-
- case DONE -> {
- if(!workDone){
- workDone = true;
- lumberjack.getCurrentLumberArea().setBeingWorkedOn(false);
- blockPos = null;
- lumberjack.setCurrentWorkArea(null);
- lumberjack.clearWorkStatus();
- this.start();
- }
- }
-
- case ERROR ->{
- if(!errorMessageDone){
- errorMessageDone = true;
- }
- }
- }
- }
-
- public void setState(State state) {
- //if(lumberjack.getOwner() != null) lumberjack.getOwner().sendSystemMessage(Component.literal(state.toString()));
- this.state = state;
- }
-
- int blockBreakTime;
- public boolean breakBlocks(Stack positions){
- if(positions != null){
- if(blockPos == null){
- if(!positions.isEmpty()) blockPos = positions.pop();
- return blockPos != null;
- }
-
- BlockState state = lumberjack.getCommandSenderWorld().getBlockState(blockPos);
- if(state.isAir()){
- if(!positions.isEmpty()){
- blockPos = positions.pop();
- }
- else{
- this.blockPos = null;
- return false;
- }
- blockBreakTime = 0;
-
- }
- else{
- this.lumberjack.mineBlock(blockPos);
- this.lumberjack.swing(InteractionHand.MAIN_HAND);
- }
- return true;
- }
- return false;
- }
-
- public boolean stripLogs(Stack positions){
- if(positions != null){
- if(blockPos == null){
- if(!positions.isEmpty()) blockPos = positions.pop();
- return blockPos != null;
- }
-
- BlockState state = lumberjack.getCommandSenderWorld().getBlockState(blockPos);
- if(AxeItem.STRIPPABLES.containsValue(state.getBlock())){
- if(!positions.isEmpty()){
- blockPos = positions.pop();
- }
- else{
- this.blockPos = null;
- return false;
- }
- }
- else{
- Block strippedBlock = AxeItem.STRIPPABLES.get(state.getBlock());
-
- if(strippedBlock == null){
- this.blockPos = null;
- return false;
- }
-
- this.lumberjack.getCommandSenderWorld().setBlock(blockPos, strippedBlock.defaultBlockState(), 3);
- this.lumberjack.getCommandSenderWorld().playSound(null, blockPos, SoundEvents.AXE_STRIP, SoundSource.BLOCKS, 1.0F, 1.0F);
-
- this.lumberjack.swing(InteractionHand.MAIN_HAND);
- }
- return true;
- }
- return false;
- }
-
- public boolean shearLeaves(Stack positions){
- if(positions != null){
- if(blockPos == null){
- if(!positions.isEmpty()) blockPos = positions.pop();
- return blockPos != null;
- }
-
- BlockState state = lumberjack.getCommandSenderWorld().getBlockState(blockPos);
- if(state.isAir()){
- if(!positions.isEmpty()){
- blockPos = positions.pop();
- }
- else{
- this.blockPos = null;
- return false;
- }
- blockBreakTime = 0;
- }
- else{
- this.lumberjack.mineBlock(blockPos);
- this.lumberjack.swing(InteractionHand.MAIN_HAND);
- }
- return true;
- }
- return false;
- }
-
- public boolean plantSaplings(Stack positions){
- if(positions != null){
- ItemStack saplingFromInv;
- if(lumberjack.getCurrentLumberArea().getSaplingStack().isEmpty()){
- saplingFromInv = lumberjack.getMatchingItem(itemStack -> itemStack.getItem() instanceof BlockItem blockItem && blockItem.getBlock() instanceof SaplingBlock);
- if(saplingFromInv == null){
- lumberjack.addNeededItem(new NeededItem(itemStack -> itemStack.getItem() instanceof BlockItem blockItem && blockItem.getBlock() instanceof SaplingBlock, 8, false));
- this.blockPos = null;
- return false;
- }
-
- }
- else{
- saplingFromInv = lumberjack.getMatchingItem(itemStack -> itemStack.is(lumberjack.getCurrentLumberArea().getSaplingStack().getItem()));
- if(saplingFromInv == null){
- lumberjack.addNeededItem(new NeededItem(itemStack -> ItemStack.isSameItemSameComponents(itemStack, lumberjack.getCurrentLumberArea().getSaplingStack()), 8, false));
- this.blockPos = null;
- return false;
- }
- }
-
- if(blockPos == null){
- if(!positions.isEmpty()) blockPos = positions.pop();
- return blockPos != null;
- }
-
- BlockState state = lumberjack.getCommandSenderWorld().getBlockState(blockPos);
- if(!state.isAir()){
- if(!positions.isEmpty()){
- blockPos = positions.pop();
- }
- else{
- this.blockPos = null;
- return false;
- }
- }
- else if (saplingFromInv.getItem() instanceof BlockItem blockItem) {
- lumberjack.getCommandSenderWorld().setBlockAndUpdate(blockPos, blockItem.getBlock().defaultBlockState());
-
- lumberjack.getCommandSenderWorld().playSound(null, blockPos.getX(), blockPos.getY(), blockPos.getZ(), SoundEvents.CROP_PLANTED, SoundSource.BLOCKS, 1.0F, 1.0F);
- saplingFromInv.shrink(1);
- this.lumberjack.swing(InteractionHand.MAIN_HAND);
- }
- return true;
- }
- this.blockPos = null;
- return false;
- }
- @Override
- public boolean canContinueToUse() {
- return canUse();
- }
-
- @Override
- public boolean isInterruptable() {
- return true;
- }
-
- @Override
- public boolean requiresUpdateEveryTick() {
- return true;
- }
-
- public static List getAvailableWorkAreasByPriority(ServerLevel level, LumberjackEntity lumberjack, @Nullable LumberArea currentArea) {
- List list = com.talhanation.bannermod.entity.civilian.workarea.WorkAreaIndex.instance()
- .queryInRange(lumberjack, 64, LumberArea.class);
-
- Map priorityMap = new HashMap<>();
-
- for (LumberArea area : list) {
- if (area == null || area == currentArea || !area.canWorkHere(lumberjack)) continue;
-
- int priority = 0;
-
- boolean perfectCandidate = area.isWorkerPerfectCandidate(lumberjack);
-
- if (perfectCandidate) {
- priority += 10;
- } else {
- priority += 1;
- }
-
- if (!area.isBeingWorkedOn()) {
- priority += 3;
- }
-
- priority += area.time;
- priority += WorkerBindingResume.priorityBoost(lumberjack.getBoundWorkAreaUUID(), area.getUUID());
-
- //double dist = area.position().distanceToSqr(lumberjack.position());
- //priority -= dist / 10.0;
-
- priorityMap.put(area, priority);
- }
-
- List sorted = new ArrayList<>(priorityMap.keySet());
- sorted.sort((a, b) -> Integer.compare(priorityMap.get(b), priorityMap.get(a)));
-
- return sorted;
- }
-
-
-
- public boolean moveToPosition(BlockPos pos, int threshold){
- if(pos == null){
- return false;
- }
- else{
- double distance = lumberjack.getHorizontalDistanceTo(pos.getCenter());
- if(distance < threshold){
- lastPathRequestPos = null;
- return false;
- }
- else{
- if(shouldRequestPath(pos)){
- lumberjack.getNavigation().moveTo(pos.getX(), pos.getY(), pos.getZ(), 0.8F);
- }
- lumberjack.setFollowState(6); //Working
- lumberjack.getLookControl().setLookAt(pos.getCenter());
- }
- return true;
- }
- }
-
- private boolean shouldRequestPath(BlockPos pos) {
- if(!pos.equals(lastPathRequestPos) || lumberjack.tickCount - lastPathRequestTick >= PATH_REQUEST_COOLDOWN_TICKS){
- lastPathRequestPos = pos;
- lastPathRequestTick = lumberjack.tickCount;
- return true;
- }
- return false;
- }
-
- public enum State{
- SELECT_WORK_AREA,
- MOVE_TO_WORK_AREA,
- SCAN_TREES,
- SELECT_TREE,
- MOVE_TO_TREE,
- PREPARE_SHEAR_LEAVES,
- SHEAR_LEAVES,
- PREPARE_STRIP_LOGS,
- STRIP_WOOD,
- PREPARE_WOOD_CUTTING,
- WOOD_CUTTING,
- PREPARE_PLANT_SAPLINGS,
- PLANT_SAPLINGS,
- DONE,
- ERROR
-
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/ai/civilian/MerchantWorkGoal.java b/src/main/java/com/talhanation/bannermod/ai/civilian/MerchantWorkGoal.java
deleted file mode 100644
index 493868bb..00000000
--- a/src/main/java/com/talhanation/bannermod/ai/civilian/MerchantWorkGoal.java
+++ /dev/null
@@ -1,193 +0,0 @@
-package com.talhanation.bannermod.ai.civilian;
-
-import com.talhanation.bannermod.entity.civilian.MerchantEntity;
-import com.talhanation.bannermod.entity.civilian.WorkerBindingResume;
-import com.talhanation.bannermod.entity.civilian.workarea.MarketArea;
-import net.minecraft.core.BlockPos;
-import net.minecraft.network.chat.Component;
-import net.minecraft.server.level.ServerLevel;
-import net.minecraft.world.entity.ai.goal.Goal;
-import net.minecraft.world.entity.player.Player;
-import net.minecraft.world.phys.AABB;
-
-import javax.annotation.Nullable;
-import java.util.*;
-
-public class MerchantWorkGoal extends Goal {
-
- private final MerchantEntity merchant;
- private State state;
- private int cooldown;
-
- public MerchantWorkGoal(MerchantEntity merchant) {
- this.merchant = merchant;
- setFlags(EnumSet.of(Flag.LOOK, Flag.MOVE));
- }
- @Override
- public boolean canUse() {
- if (merchant.isCreative()) return false;
- return merchant.shouldWork() && !merchant.needsToGetToChest();
- }
-
- @Override
- public boolean canContinueToUse() {
- return canUse();
- }
-
- @Override
- public boolean isInterruptable(){
- return true;
- }
-
- @Override
- public boolean requiresUpdateEveryTick(){
- return true;
- }
-
- @Override
- public void start() {
- setState(State.SELECT_WORK_AREA);
- }
-
- @Override
- public void stop() {
- MarketArea market = merchant.getCurrentMarketArea();
- if (market != null) {
- market.setBeingWorkedOn(false);
- merchant.setCurrentWorkArea(null);
- merchant.setCurrentMarketName("");
- }
- merchant.getNavigation().stop();
- }
-
- @Override
- public void tick() {
- if (merchant.getCommandSenderWorld().isClientSide()) return;
- if (state == null) return;
-
- if (state != State.SELECT_WORK_AREA && isCurrentAreaGone()) {
- leaveCurrentArea();
- setState(State.SELECT_WORK_AREA);
- return;
- }
-
- switch (state) {
- case SELECT_WORK_AREA -> {
- if (merchant.getCurrentMarketArea() != null) {
- setState(State.WALK_TO_CENTER);
- return;
- }
-
- if (++cooldown < merchant.getRandom().nextInt(200)) return;
- cooldown = 0;
-
- MarketArea found = findBestArea((ServerLevel) merchant.getCommandSenderWorld());
- if (found == null) {
- merchant.reportIdleReason("merchant_no_market", Component.literal(merchant.getName().getString() + ": Waiting for an open market area."));
- return;
- }
-
- merchant.setCurrentWorkArea(found);
- merchant.clearWorkStatus();
- found.setBeingWorkedOn(true);
- found.setTime(0);
-
- merchant.setCurrentMarketName(found.getMarketName());
- setState(State.WALK_TO_CENTER);
- }
-
- case WALK_TO_CENTER -> {
- if (moveToPosition(BlockPos.containing(merchant.getCurrentMarketArea().getArea().getCenter()), 3)) return;
- merchant.getNavigation().stop();
- setState(State.WORKING);
- }
-
- case WORKING -> {
- if (!merchant.getCurrentMarketArea().isOpen()) {
- merchant.reportIdleReason("merchant_market_closed", Component.literal(merchant.getName().getString() + ": My market is currently closed."));
- leaveCurrentArea();
- setState(State.SELECT_WORK_AREA);
- return;
- }
-
- merchant.clearWorkStatus();
- merchant.getNavigation().stop();
- merchant.setFollowState(6);
-
- Player nearby = merchant.getCommandSenderWorld()
- .getNearestPlayer(merchant, 8);
- if (nearby != null) {
- merchant.getLookControl().setLookAt(nearby, 30, 30);
- }
- else {
- merchant.setYRot(merchant.getCurrentMarketArea().getFacing().getOpposite().toYRot());
- }
-
- merchant.setCurrentMarketName(merchant.getCurrentMarketArea().getMarketName());
- }
- }
- }
-
- private void leaveCurrentArea() {
- MarketArea market = merchant.getCurrentMarketArea();
- if (market != null) {
- market.setBeingWorkedOn(false);
- merchant.setCurrentWorkArea(null);
- merchant.setCurrentMarketName("");
- }
- }
-
- private boolean isCurrentAreaGone() {
- MarketArea market = merchant.getCurrentMarketArea();
- return market == null || market.isRemoved();
- }
-
-
- private boolean moveToPosition(BlockPos pos, int thresholdBlocks) {
- double dist = merchant.getHorizontalDistanceTo(pos.getCenter());
- if (dist < thresholdBlocks) {
- merchant.getNavigation().stop();
- return false;
- }
- merchant.getNavigation().moveTo(pos.getX(), pos.getY(), pos.getZ(), 0.8F);
- merchant.setFollowState(6);
- merchant.getLookControl().setLookAt(pos.getCenter());
- return true;
- }
-
- @Nullable
- private MarketArea findBestArea(ServerLevel level) {
- List areas = com.talhanation.bannermod.entity.civilian.workarea.WorkAreaIndex.instance()
- .queryInRange(merchant, 64, MarketArea.class);
-
- WorkerBindingResume.prioritizeBoundFirst(areas, merchant.getBoundWorkAreaUUID(), MarketArea::getUUID);
-
- MarketArea best = null;
- int bestScore = -1;
-
- for (MarketArea area : areas) {
- if (area == null) continue;
- if (!area.canWorkHere(merchant)) continue;
- if (area.isBeingWorkedOn()) continue;
- int score = 0;
- score += area.getTime() * 10;
- score += WorkerBindingResume.priorityBoost(merchant.getBoundWorkAreaUUID(), area.getUUID());
-
- if (score > bestScore) {
- bestScore = score;
- best = area;
- }
- }
- return best;
- }
-
- private void setState(State s) {
- this.state = s;
- }
-
- public enum State {
- SELECT_WORK_AREA,
- WALK_TO_CENTER,
- WORKING
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/ai/civilian/MinerWorkGoal.java b/src/main/java/com/talhanation/bannermod/ai/civilian/MinerWorkGoal.java
deleted file mode 100644
index 182c51af..00000000
--- a/src/main/java/com/talhanation/bannermod/ai/civilian/MinerWorkGoal.java
+++ /dev/null
@@ -1,525 +0,0 @@
-package com.talhanation.bannermod.ai.civilian;
-
-import com.google.common.collect.ImmutableSet;
-import com.talhanation.bannermod.entity.civilian.MinerEntity;
-import com.talhanation.bannermod.entity.civilian.WorkerBindingResume;
-import com.talhanation.bannermod.entity.civilian.workarea.MiningArea;
-import com.talhanation.bannermod.persistence.civilian.NeededItem;
-import net.minecraft.core.BlockPos;
-import net.minecraft.network.chat.Component;
-import net.minecraft.server.level.ServerLevel;
-import net.minecraft.sounds.SoundEvents;
-import net.minecraft.sounds.SoundSource;
-import net.minecraft.world.InteractionHand;
-import net.minecraft.world.entity.ai.goal.Goal;
-import net.minecraft.world.item.BlockItem;
-import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.item.Items;
-import net.minecraft.world.item.PickaxeItem;
-import net.minecraft.world.level.ClipContext;
-import net.minecraft.world.level.Level;
-import net.minecraft.world.level.block.Blocks;
-import net.minecraft.world.level.block.state.BlockState;
-import net.minecraft.world.level.material.FluidState;
-import net.minecraft.world.phys.Vec3;
-
-import javax.annotation.Nullable;
-import java.util.*;
-
-public class MinerWorkGoal extends Goal {
-
- private static final int AREA_SEARCH_COOLDOWN_TICKS = 20;
- private static final int PATH_REQUEST_COOLDOWN_TICKS = 20;
-
- public MinerEntity minerEntity;
- public State state;
- public String errorMessage;
- public boolean errorMessageDone;
- public BlockPos blockPos;
- public Stack stackToBreak;
- public Stack stackToPlace;
- private boolean needToSeeBlock;
- private int lastAreaSearchTick = -AREA_SEARCH_COOLDOWN_TICKS;
- private int lastPathRequestTick = -PATH_REQUEST_COOLDOWN_TICKS;
- @Nullable
- private BlockPos lastPathRequestPos;
-
- public MinerWorkGoal(MinerEntity minerEntity) {
- this.minerEntity = minerEntity;
- setFlags(EnumSet.of(Flag.LOOK, Flag.MOVE));
- }
-
- @Override
- public boolean canUse() {
- return !minerEntity.needsToSleep() && minerEntity.shouldWork() && !minerEntity.needsToGetToChest() && this.isMiningAreaAvailable();
- }
-
- @Override
- public void start() {
- super.start();
- if(this.minerEntity.getCommandSenderWorld().isClientSide()) return;
-
-
- setState(State.SELECT_WORK_AREA);
- }
- boolean workDone;
- @Override
- public void tick() {
- super.tick();
- if(this.minerEntity.getCommandSenderWorld().isClientSide()) return;
- if(state == null) return;
- if(blockPos != null) this.minerEntity.getLookControl().setLookAt(blockPos.getCenter());
-
- if(!isMiningAreaAvailable()) return;
-
- if(checkPlaceTorch()) return;
-
- if(state != State.SELECT_WORK_AREA && this.minerEntity.getCurrentMiningArea() == null){
- this.blockPos = null;
- setState(State.SELECT_WORK_AREA);
- return;
- }
-
- if(minerEntity.tickCount % 20 == 0){
- if(blockPos != null && moveToPosition(blockPos, 20)) return;
- }
-
- if(state == State.MINING){
- if(this.mineBlocks(this.stackToBreak)) return;
-
- setState(State.PREPARE_MINE_WALLS);
- }
-
- if(state == State.MINE_WALLS){
- if(this.mineBlocks(this.stackToBreak)) return;
-
- setState(State.CHECK);
- }
-
- if(minerEntity.tickCount % 5 != 0) return;
- switch(state){
- case SELECT_WORK_AREA ->{
- if(minerEntity.getCurrentMiningArea() != null) setState(State.MOVE_TO_WORK_AREA);
-
- if(minerEntity.tickCount - lastAreaSearchTick < AREA_SEARCH_COOLDOWN_TICKS) return;
- lastAreaSearchTick = minerEntity.tickCount;
-
- List areas = getAvailableWorkAreasByPriority((ServerLevel) minerEntity.getCommandSenderWorld(), minerEntity, minerEntity.getCurrentMiningArea());
-
- if (!areas.isEmpty()) {
- minerEntity.setCurrentWorkArea(areas.get(0));
- }
-
- if(minerEntity.getCurrentMiningArea() == null) {
- minerEntity.reportIdleReason("miner_no_area", Component.literal(minerEntity.getName().getString() + ": Waiting for a mining area."));
- return;
- }
-
- minerEntity.clearWorkStatus();
- minerEntity.getCurrentMiningArea().setBeingWorkedOn(true);
- this.minerEntity.getCurrentMiningArea().setTime(0);
- this.minerEntity.getCurrentMiningArea().resetPatternProgress();
- workDone = false;
- setState(State.MOVE_TO_WORK_AREA);
- }
-
- case MOVE_TO_WORK_AREA ->{
- this.blockPos = null;
- if(this.moveToPosition(minerEntity.getCurrentMiningArea().getOnPos(), 70)) return;
-
- setState(State.PREPARE_CLOSE_FLOOR);
- }
-
- case PREPARE_MINING -> {
- this.blockPos = null;
-
- if(this.minerEntity.getCurrentMiningArea().stackToBreak.isEmpty()){
- this.minerEntity.getCurrentMiningArea().scanBreakArea();
- }
-
- this.stackToBreak = this.minerEntity.getCurrentMiningArea().stackToBreak;
-
- if(stackToBreak.isEmpty()){
- setState(State.PREPARE_MINE_WALLS);
- return;
- }
-
- minerEntity.switchMainHandItem(itemStack -> itemStack.getItem() instanceof PickaxeItem);
-
- boolean hasAxe = minerEntity.getMainHandItem().getItem() instanceof PickaxeItem;
- if(!hasAxe){
- minerEntity.requestRequiredItem(new NeededItem(stack -> stack.getItem() instanceof PickaxeItem, 1, true),
- "miner_missing_pickaxe",
- Component.literal(minerEntity.getName().getString() + ": I need a pickaxe to continue."));
- this.blockPos = null;
- return;
- }
-
- boolean hasShovel = minerEntity.getInventory().hasAnyMatching(itemStack -> itemStack.getItem() instanceof PickaxeItem);
- if(!hasShovel){
- minerEntity.requestRequiredItem(new NeededItem(stack -> stack.getItem() instanceof PickaxeItem, 1, true),
- "miner_missing_pickaxe",
- Component.literal(minerEntity.getName().getString() + ": I need a pickaxe to continue."));
- this.blockPos = null;
- return;
- }
-
- needToSeeBlock = true;
- setState(State.MINING);
- }
-
- case PREPARE_MINE_WALLS -> {
- this.minerEntity.getCurrentMiningArea().scanForOresOnWalls();
-
- this.stackToBreak = minerEntity.getCurrentMiningArea().stackToBreak;
- if(stackToBreak.isEmpty()){
- setState(State.CHECK);
- return;
- }
-
- minerEntity.switchMainHandItem(itemStack -> itemStack.getItem() instanceof PickaxeItem);
-
- boolean hasAxe = minerEntity.getMainHandItem().getItem() instanceof PickaxeItem;
- if(!hasAxe){
- minerEntity.requestRequiredItem(new NeededItem(stack -> stack.getItem() instanceof PickaxeItem, 1, true),
- "miner_missing_pickaxe",
- Component.literal(minerEntity.getName().getString() + ": I need a pickaxe to continue."));
- this.blockPos = null;
- return;
- }
- needToSeeBlock = false;
- setState(State.MINE_WALLS);
- }
-
- case PREPARE_CLOSE_FLOOR -> {
- if(!this.minerEntity.getCurrentMiningArea().getCloseFloor()){
- setState(State.PREPARE_MINING);
- return;
- }
-
- if(minerEntity.getCurrentMiningArea().stackToPlace.isEmpty()){
- this.minerEntity.getCurrentMiningArea().scanFloorArea();
- }
-
- this.stackToPlace = minerEntity.getCurrentMiningArea().stackToPlace;
-
- if(stackToPlace.isEmpty()){
- setState(State.PREPARE_MINING);
- return;
- }
-
- setState(State.CLOSE_FLOOR);
- }
-
- case CLOSE_FLOOR -> {
- if(!this.minerEntity.getCurrentMiningArea().getCloseFloor()){
- setState(State.PREPARE_MINING);
- return;
- }
-
- minerEntity.switchMainHandItem(itemStack -> itemStack.is(Items.COBBLESTONE));
-
- if(this.closeHoles(this.stackToPlace)) return;
-
- setState(State.PREPARE_MINING);
- }
-
- case CHECK -> {
- this.minerEntity.getCurrentMiningArea().scanBreakArea();
- this.stackToBreak = this.minerEntity.getCurrentMiningArea().stackToBreak;
-
- if(stackToBreak.isEmpty()){
- if (this.minerEntity.getCurrentMiningArea().getMiningMode() == MiningArea.MiningMode.TUNNEL
- || this.minerEntity.getCurrentMiningArea().getMiningMode() == MiningArea.MiningMode.BRANCH) {
- if (this.minerEntity.getCurrentMiningArea().advancePatternSegment()) {
- setState(State.PREPARE_CLOSE_FLOOR);
- return;
- }
- }
- setState(State.DONE);
- }
- else{
- setState(State.PREPARE_CLOSE_FLOOR);
- }
- }
-
- case DONE -> {
- this.minerEntity.getCurrentMiningArea().setDone(true);
-
- blockPos = null;
- minerEntity.setCurrentWorkArea(null);
- this.start();
- minerEntity.clearWorkStatus();
-
- this.minerEntity.forcedDeposit = true;
- }
-
- case ERROR ->{
- if(!errorMessageDone){
- errorMessageDone = true;
- }
- }
- }
- }
-
- private boolean checkPlaceTorch() {
- if(minerEntity.getCommandSenderWorld().getRawBrightness(minerEntity.getOnPos().above(), 0) <= 7){
- BlockState onPosState = minerEntity.getCommandSenderWorld().getBlockState(minerEntity.getOnPos());
- BlockState stateAbove = minerEntity.getCommandSenderWorld().getBlockState(minerEntity.getOnPos().above());
- if(stateAbove.isAir() && !onPosState.isAir()){
- placeTorch();
- return true;
- }
-
- }
- return false;
- }
-
- public void placeTorch(){
- if (minerEntity.getInventory().hasAnyOf(ImmutableSet.of(Items.TORCH))){
- minerEntity.switchMainHandItem(itemStack -> itemStack.is(Items.TORCH));
-
- minerEntity.getCommandSenderWorld().setBlock(minerEntity.getOnPos().above(), Blocks.TORCH.defaultBlockState(), 3);
- minerEntity.getCommandSenderWorld().playSound(null, this.minerEntity.getX(), this.minerEntity.getY(), this.minerEntity.getZ(), SoundEvents.WOOD_PLACE, SoundSource.BLOCKS, 1.0F, 1.0F);
-
- for (int i = 0; i < minerEntity.getInventory().getContainerSize(); ++i) {
- ItemStack itemstack = minerEntity.getInventory().getItem(i);
- if(itemstack.is(Items.TORCH)) itemstack.shrink(1);
- }
- }
- else{
- NeededItem torch = new NeededItem(itemStack -> itemStack.is(Items.TORCH), 16, true);
- if(!minerEntity.neededItems.contains(torch)) minerEntity.addNeededItem(torch);
- }
- }
-
- private boolean isMiningAreaAvailable() {
- MiningArea area = minerEntity.getCurrentMiningArea();
- if(area == null || !area.isRemoved()) return true;
- else {
- minerEntity.setCurrentWorkArea(null);
- }
- return false;
- }
-
- public void setState(State state) {
- //if(minerEntity.getOwner() != null) minerEntity.getOwner().sendSystemMessage(Component.literal(state.toString()));
- this.state = state;
- }
-
- int blockBreakTime;
- public boolean mineBlocks(Stack positions){
- if(positions != null){
- if(blockPos == null){
- if(!positions.isEmpty()){
- blockPos = this.getNewMiningPosition(positions);
- }
- return blockPos != null;
- }
-
- BlockState state = minerEntity.getCommandSenderWorld().getBlockState(blockPos);
- if(state.isAir() || minerEntity.shouldIgnoreBlock(state)){
- if(!positions.isEmpty()){
- blockPos = this.getNewMiningPosition(positions);
- }
- else{
- this.blockPos = null;
- return false;
- }
- blockBreakTime = 0;
- }
- else{
- this.minerEntity.changeTool(state);
-
- this.minerEntity.mineBlock(blockPos);
- this.minerEntity.swing(InteractionHand.MAIN_HAND);
- }
- return true;
- }
- return false;
- }
-
- private BlockPos getNewMiningPosition(Stack positions) {
- BlockPos newPosition = null;
-
- if(blockPos == null){
- if(this.needToSeeBlock){
- positions.removeIf(pos ->
- !canSeeBlock(minerEntity.getCommandSenderWorld(), minerEntity.position().add(0, 1, 0), pos)
- );
-
- }
-
- if(positions.isEmpty()){
- setState(State.MOVE_TO_WORK_AREA);
- return null;
- }
-
- newPosition = MiningPositionSelection.popNearest(positions, minerEntity.position());
- }
- else if(positions.contains(blockPos.above())){
- newPosition = blockPos.above();
- }
- else if(positions.contains(blockPos.below())){
- newPosition = blockPos.below();
- }
- else{
- newPosition = MiningPositionSelection.popNearest(positions, minerEntity.position());
- }
- return newPosition;
- }
-
- //PERFORMANCE HEAVY DO NOT USE FREQUENTLY
- private boolean canSeeBlock(Level level, Vec3 start, BlockPos target) {
- Vec3 targetCenter = target.getCenter();
- ClipContext ctx = new ClipContext(start, targetCenter, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, minerEntity);
- BlockPos ctxPos = level.clip(ctx).getBlockPos();
- return ctxPos.equals(target);
- }
-
- public boolean closeHoles(Stack positions){
- if(positions != null){
- ItemStack cobbleBlockFromInv;
-
- cobbleBlockFromInv = minerEntity.getMatchingItem(itemStack -> itemStack.getItem() instanceof BlockItem blockItem && blockItem.getBlock().defaultBlockState().is(Blocks.COBBLESTONE));
- if(cobbleBlockFromInv == null){
- minerEntity.addNeededItem(new NeededItem(itemStack -> itemStack.getItem() instanceof BlockItem blockItem && blockItem.getBlock().defaultBlockState().is(Blocks.COBBLESTONE), 16, true));
- this.blockPos = null;
- return false;
- }
-
- if(blockPos == null){
- if(!positions.isEmpty()){
- blockPos = positions.pop();
- }
- else{
- return false;
- }
- }
-
- BlockState state = minerEntity.getCommandSenderWorld().getBlockState(blockPos);
- FluidState fluid = minerEntity.getCommandSenderWorld().getFluidState(blockPos);
- if(!state.isAir() && fluid.isEmpty()){
- if(!positions.isEmpty()){
- blockPos = positions.pop();
- }
- else{
- return false;
- }
- }
- else if(cobbleBlockFromInv.getItem() instanceof BlockItem blockItem) {
- minerEntity.getCommandSenderWorld().setBlockAndUpdate(blockPos, blockItem.getBlock().defaultBlockState());
- minerEntity.getCommandSenderWorld().playSound(null, blockPos.getX(), blockPos.getY(), blockPos.getZ(), SoundEvents.STONE_PLACE, SoundSource.BLOCKS, 1.0F, 1.0F);
- cobbleBlockFromInv.shrink(1);
- this.minerEntity.swing(InteractionHand.MAIN_HAND);
- }
- return true;
- }
- this.blockPos = null;
- return false;
- }
- @Override
- public boolean canContinueToUse() {
- return canUse();
- }
-
- @Override
- public boolean isInterruptable() {
- return true;
- }
-
- @Override
- public boolean requiresUpdateEveryTick() {
- return true;
- }
-
- public static List getAvailableWorkAreasByPriority(ServerLevel level, MinerEntity minerEntity, @Nullable MiningArea currentArea) {
- List list = com.talhanation.bannermod.entity.civilian.workarea.WorkAreaIndex.instance()
- .queryInRange(minerEntity, 64, MiningArea.class);
-
- Map priorityMap = new HashMap<>();
-
- for (MiningArea area : list) {
- if (area == null || area == currentArea || !area.canWorkHere(minerEntity)) continue;
-
- if(area.isDone()) continue;
-
- int priority = 0;
-
- boolean perfectCandidate = area.isWorkerPerfectCandidate(minerEntity);
-
- if (perfectCandidate) {
- priority += 10;
- } else {
- priority += 1;
- }
-
- if (!area.isBeingWorkedOn()) {
- priority += 3;
- }
-
- priority += area.time;
- priority += WorkerBindingResume.priorityBoost(minerEntity.getBoundWorkAreaUUID(), area.getUUID());
-
- //double dist = area.position().distanceToSqr(minerEntity.position());
- //priority -= dist / 10.0;
-
- priorityMap.put(area, priority);
- }
-
-
- List sorted = new ArrayList<>(priorityMap.keySet());
- sorted.sort((a, b) -> Integer.compare(priorityMap.get(b), priorityMap.get(a)));
-
- return sorted;
- }
-
-
-
- public boolean moveToPosition(BlockPos pos, int threshold){
- if(pos == null){
- return false;
- }
- else{
- double distance = minerEntity.getHorizontalDistanceTo(pos.getCenter());
- if(distance < threshold){
- minerEntity.getNavigation().stop();
- lastPathRequestPos = null;
- return false;
- }
- else{
-
- minerEntity.setFollowState(6); //Working
- if(shouldRequestPath(pos)){
- minerEntity.getNavigation().moveTo(pos.getX(), pos.getY(), pos.getZ(), 0.8F);
- }
- minerEntity.getLookControl().setLookAt(pos.getCenter());
- }
- return true;
- }
- }
-
- private boolean shouldRequestPath(BlockPos pos) {
- if(!pos.equals(lastPathRequestPos) || minerEntity.tickCount - lastPathRequestTick >= PATH_REQUEST_COOLDOWN_TICKS){
- lastPathRequestPos = pos;
- lastPathRequestTick = minerEntity.tickCount;
- return true;
- }
- return false;
- }
-
- public enum State{
- SELECT_WORK_AREA,
- MOVE_TO_WORK_AREA,
- PREPARE_MINE_WALLS,
- MINE_WALLS,
- PREPARE_CLOSE_FLOOR,
- CLOSE_FLOOR,
- PREPARE_MINING,
- MINING,
- CHECK,
- DONE,
- ERROR
-
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/ai/civilian/SettlementOrderWorkGoal.java b/src/main/java/com/talhanation/bannermod/ai/civilian/SettlementOrderWorkGoal.java
index c4cea1d2..40664404 100644
--- a/src/main/java/com/talhanation/bannermod/ai/civilian/SettlementOrderWorkGoal.java
+++ b/src/main/java/com/talhanation/bannermod/ai/civilian/SettlementOrderWorkGoal.java
@@ -1,17 +1,23 @@
package com.talhanation.bannermod.ai.civilian;
import com.talhanation.bannermod.entity.civilian.AbstractWorkerEntity;
+import com.talhanation.bannermod.entity.civilian.AnimalFarmerEntity;
+import com.talhanation.bannermod.entity.civilian.FishermanEntity;
+import com.talhanation.bannermod.entity.civilian.FishingBobberEntity;
+import com.talhanation.bannermod.entity.civilian.workarea.AnimalPenArea;
import com.talhanation.bannermod.entity.civilian.workarea.BuildArea;
import com.talhanation.bannermod.entity.civilian.workarea.StorageArea;
import com.talhanation.bannermod.entity.civilian.workarea.WorkAreaIndex;
import com.talhanation.bannermod.persistence.civilian.BuildBlockParse;
-import com.talhanation.bannermod.settlement.BannerModSettlementOrchestrator;
+import com.talhanation.bannermod.persistence.civilian.NeededItem;
+import com.talhanation.bannermod.settlement.SettlementOrchestrator;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrder;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrderRuntime;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrderType;
import com.talhanation.bannermod.shared.logistics.BannerModLogisticsItemFilter;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
+import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
@@ -19,9 +25,16 @@
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ai.goal.Goal;
+import net.minecraft.world.entity.animal.Animal;
+import net.minecraft.world.entity.animal.Cow;
+import net.minecraft.world.entity.animal.Sheep;
+import net.minecraft.world.entity.projectile.ThrownEgg;
+import net.minecraft.world.item.AxeItem;
import net.minecraft.world.item.BlockItem;
+import net.minecraft.world.item.FishingRodItem;
import net.minecraft.world.item.HoeItem;
import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.ChestBlock;
@@ -31,6 +44,7 @@
import net.minecraft.world.level.block.StemBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.common.SpecialPlantable;
@@ -91,7 +105,7 @@ public boolean canUse() {
if (!(worker.getCommandSenderWorld() instanceof ServerLevel level)) {
return false;
}
- SettlementWorkOrderRuntime runtime = BannerModSettlementOrchestrator.workOrderRuntime(level);
+ SettlementWorkOrderRuntime runtime = SettlementOrchestrator.workOrderRuntime(level);
if (runtime == null) {
return false;
}
@@ -107,7 +121,7 @@ public boolean canContinueToUse() {
if (!(worker.getCommandSenderWorld() instanceof ServerLevel level)) {
return false;
}
- SettlementWorkOrderRuntime runtime = BannerModSettlementOrchestrator.workOrderRuntime(level);
+ SettlementWorkOrderRuntime runtime = SettlementOrchestrator.workOrderRuntime(level);
if (runtime == null) {
return false;
}
@@ -120,7 +134,7 @@ public void start() {
if (!(worker.getCommandSenderWorld() instanceof ServerLevel level)) {
return;
}
- SettlementWorkOrderRuntime runtime = BannerModSettlementOrchestrator.workOrderRuntime(level);
+ SettlementWorkOrderRuntime runtime = SettlementOrchestrator.workOrderRuntime(level);
if (runtime == null) {
return;
}
@@ -155,7 +169,7 @@ public void tick() {
if (!(worker.getCommandSenderWorld() instanceof ServerLevel level)) {
return;
}
- SettlementWorkOrderRuntime runtime = BannerModSettlementOrchestrator.workOrderRuntime(level);
+ SettlementWorkOrderRuntime runtime = SettlementOrchestrator.workOrderRuntime(level);
if (runtime == null) {
return;
}
@@ -362,6 +376,10 @@ private void executeAt(ServerLevel level, BlockPos target, SettlementWorkOrderRu
case TILL_SOIL -> executeTillSoil(level, target, runtime);
case PLANT_CROP -> executePlantCrop(level, target, runtime);
case REPLANT_TREE -> executeReplantTree(level, target, runtime);
+ case FISH -> executeFish(target, runtime, level);
+ case ANIMAL_BREED -> executeAnimalBreed(level, target, runtime);
+ case ANIMAL_SPECIAL_TASK -> executeAnimalSpecialTask(level, target, runtime);
+ case ANIMAL_SLAUGHTER -> executeAnimalSlaughter(level, target, runtime);
case BUILD_BLOCK -> executeBuildBlock(level, target, runtime);
default -> {
// Placement-style or specialist types are left to legacy profession goals.
@@ -371,6 +389,209 @@ private void executeAt(ServerLevel level, BlockPos target, SettlementWorkOrderRu
}
}
+ private void executeFish(BlockPos target, SettlementWorkOrderRuntime runtime, ServerLevel level) {
+ if (!(worker instanceof FishermanEntity fisherman)) {
+ runtime.release(activeOrder.orderUuid());
+ this.activeOrder = null;
+ return;
+ }
+ if (!fisherman.hasFreeInvSlot()) {
+ fisherman.reportBlockedReason("fisherman_inventory_full", Component.literal(fisherman.getName().getString() + ": My inventory is full."));
+ fisherman.forcedDeposit = true;
+ runtime.release(activeOrder.orderUuid());
+ this.activeOrder = null;
+ return;
+ }
+
+ boolean hasFishingRod = fisherman.getInventory().hasAnyMatching(itemStack -> itemStack.getItem() instanceof FishingRodItem);
+ if (!hasFishingRod) {
+ fisherman.requestRequiredItem(new NeededItem(stack -> stack.getItem() instanceof FishingRodItem, 1, true),
+ "fisherman_missing_rod",
+ Component.literal(fisherman.getName().getString() + ": I need a fishing rod to continue."));
+ runtime.release(activeOrder.orderUuid());
+ this.activeOrder = null;
+ return;
+ }
+
+ fisherman.clearWorkStatus();
+ fisherman.switchMainHandItem(itemStack -> itemStack.getItem() instanceof FishingRodItem);
+ fisherman.swing(InteractionHand.MAIN_HAND);
+ fisherman.playSound(SoundEvents.FISHING_BOBBER_THROW, 1, 1);
+ FishingBobberEntity fishingBobber = fisherman.throwFishingHook(target.getCenter());
+ fisherman.playSound(SoundEvents.FISHING_BOBBER_SPLASH, 1, 1);
+ fisherman.swing(InteractionHand.MAIN_HAND);
+ fisherman.playSound(SoundEvents.FISHING_BOBBER_RETRIEVE, 1, 1);
+ fisherman.spawnFishingLoot(fishingBobber);
+ fishingBobber.discard();
+ fisherman.farmedItems++;
+ if (fisherman.tickCount % 2 == 0) {
+ fisherman.damageMainHandItem();
+ }
+ completeActiveOrder(runtime, level);
+ this.activeOrder = null;
+ }
+
+ private void executeAnimalBreed(ServerLevel level, BlockPos target, SettlementWorkOrderRuntime runtime) {
+ AnimalPenArea pen = activeAnimalPen(level, runtime);
+ if (pen == null) {
+ return;
+ }
+ if (!(worker instanceof AnimalFarmerEntity animalFarmer)) {
+ releaseActiveOrder(runtime);
+ return;
+ }
+ Animal animal = animalAt(level, pen, target);
+ if (animal == null) {
+ completeActiveOrder(runtime, level);
+ this.activeOrder = null;
+ return;
+ }
+
+ animalFarmer.switchMainHandItem(itemStack -> itemStack.is(pen.getAnimalType().getBreedItem()));
+ if (!animalFarmer.getMainHandItem().is(pen.getAnimalType().getBreedItem())) {
+ animalFarmer.requestRequiredItem(new NeededItem(stack -> stack.is(pen.getAnimalType().getBreedItem()), 1, true),
+ "animal_farmer_missing_breed_item",
+ Component.literal(animalFarmer.getName().getString() + ": I need breeding items to continue."));
+ releaseActiveOrder(runtime);
+ return;
+ }
+
+ animalFarmer.getLookControl().setLookAt(animal);
+ animalFarmer.swing(InteractionHand.MAIN_HAND);
+ animalFarmer.getMainHandItem().shrink(1);
+ animal.setAge(0);
+ animal.setInLove(null);
+ completeActiveOrder(runtime, level);
+ this.activeOrder = null;
+ }
+
+ private void executeAnimalSpecialTask(ServerLevel level, BlockPos target, SettlementWorkOrderRuntime runtime) {
+ AnimalPenArea pen = activeAnimalPen(level, runtime);
+ if (pen == null) {
+ return;
+ }
+ if (!(worker instanceof AnimalFarmerEntity animalFarmer)) {
+ releaseActiveOrder(runtime);
+ return;
+ }
+
+ if (pen.getAnimalType() == AnimalPenArea.AnimalTypes.CHICKEN) {
+ throwEggForPen(level, pen, animalFarmer, runtime);
+ return;
+ }
+
+ Animal animal = animalAt(level, pen, target);
+ if (animal == null) {
+ completeActiveOrder(runtime, level);
+ this.activeOrder = null;
+ return;
+ }
+
+ animalFarmer.switchMainHandItem(itemStack -> itemStack.is(pen.getAnimalType().getSpecialItem()));
+ if (!animalFarmer.getMainHandItem().is(pen.getAnimalType().getSpecialItem())) {
+ animalFarmer.requestRequiredItem(new NeededItem(stack -> stack.is(pen.getAnimalType().getSpecialItem()), 1, true),
+ "animal_farmer_missing_special_item",
+ Component.literal(animalFarmer.getName().getString() + ": I need the right tool or item to continue."));
+ releaseActiveOrder(runtime);
+ return;
+ }
+
+ animalFarmer.getLookControl().setLookAt(animal);
+ if (pen.getAnimalType() == AnimalPenArea.AnimalTypes.SHEEP && animal instanceof Sheep sheep) {
+ sheep.shear(SoundSource.PLAYERS);
+ sheep.setSheared(true);
+ animalFarmer.swing(InteractionHand.MAIN_HAND);
+ animalFarmer.damageMainHandItem();
+ } else if (pen.getAnimalType() == AnimalPenArea.AnimalTypes.COW && animal instanceof Cow) {
+ animalFarmer.getMainHandItem().shrink(1);
+ animalFarmer.getInventory().addItem(Items.MILK_BUCKET.getDefaultInstance());
+ animal.playSound(SoundEvents.COW_MILK, 1.0F, 1.0F);
+ }
+ completeActiveOrder(runtime, level);
+ this.activeOrder = null;
+ }
+
+ private void executeAnimalSlaughter(ServerLevel level, BlockPos target, SettlementWorkOrderRuntime runtime) {
+ AnimalPenArea pen = activeAnimalPen(level, runtime);
+ if (pen == null) {
+ return;
+ }
+ if (!(worker instanceof AnimalFarmerEntity animalFarmer)) {
+ releaseActiveOrder(runtime);
+ return;
+ }
+ Animal animal = animalAt(level, pen, target);
+ if (animal == null) {
+ completeActiveOrder(runtime, level);
+ this.activeOrder = null;
+ return;
+ }
+
+ animalFarmer.switchMainHandItem(itemStack -> itemStack.getItem() instanceof AxeItem);
+ if (!(animalFarmer.getMainHandItem().getItem() instanceof AxeItem)) {
+ animalFarmer.requestRequiredItem(new NeededItem(stack -> stack.getItem() instanceof AxeItem, 1, true),
+ "animal_farmer_missing_axe",
+ Component.literal(animalFarmer.getName().getString() + ": I need an axe to continue."));
+ releaseActiveOrder(runtime);
+ return;
+ }
+
+ animalFarmer.getLookControl().setLookAt(animal);
+ animalFarmer.playSound(SoundEvents.PLAYER_ATTACK_STRONG);
+ animalFarmer.swing(InteractionHand.MAIN_HAND);
+ animal.kill();
+ animalFarmer.damageMainHandItem();
+ completeActiveOrder(runtime, level);
+ this.activeOrder = null;
+ }
+
+ @Nullable
+ private AnimalPenArea activeAnimalPen(ServerLevel level, SettlementWorkOrderRuntime runtime) {
+ Entity entity = level.getEntity(activeOrder.buildingUuid());
+ if (entity instanceof AnimalPenArea pen && pen.isAlive()) {
+ return pen;
+ }
+ completeActiveOrder(runtime, level);
+ this.activeOrder = null;
+ return null;
+ }
+
+ @Nullable
+ private Animal animalAt(ServerLevel level, AnimalPenArea pen, BlockPos target) {
+ return level.getEntitiesOfClass(Animal.class, new AABB(target).inflate(1.0D), pen::isCorrectAnimal)
+ .stream()
+ .min(Comparator.comparingDouble(animal -> animal.distanceToSqr(target.getCenter())))
+ .orElse(null);
+ }
+
+ private void throwEggForPen(ServerLevel level, AnimalPenArea pen, AnimalFarmerEntity animalFarmer, SettlementWorkOrderRuntime runtime) {
+ animalFarmer.switchMainHandItem(itemStack -> itemStack.is(Items.EGG));
+ if (!animalFarmer.getMainHandItem().is(Items.EGG)) {
+ animalFarmer.requestRequiredItem(new NeededItem(stack -> stack.is(Items.EGG), 32, false),
+ "animal_farmer_missing_special_item",
+ Component.literal(animalFarmer.getName().getString() + ": I need the right tool or item to continue."));
+ releaseActiveOrder(runtime);
+ return;
+ }
+
+ Vec3 center = pen.getArea().getCenter();
+ level.playSound(null, animalFarmer.getX(), animalFarmer.getY(), animalFarmer.getZ(), SoundEvents.EGG_THROW, SoundSource.PLAYERS, 0.5F,
+ 0.4F / (animalFarmer.getRandom().nextFloat() * 0.4F + 0.8F));
+ ThrownEgg thrownEgg = new ThrownEgg(level, animalFarmer);
+ thrownEgg.setItem(new ItemStack(Items.EGG));
+ thrownEgg.shoot(center.x() - animalFarmer.getX(), 0, center.z() - animalFarmer.getZ(), 0.1F, 0F);
+ if (level.addFreshEntity(thrownEgg)) {
+ animalFarmer.getMainHandItem().shrink(1);
+ }
+ completeActiveOrder(runtime, level);
+ this.activeOrder = null;
+ }
+
+ private void releaseActiveOrder(SettlementWorkOrderRuntime runtime) {
+ runtime.release(activeOrder.orderUuid());
+ this.activeOrder = null;
+ }
+
private static boolean isExecutableOrder(SettlementWorkOrder order) {
if (order == null) {
return false;
@@ -382,7 +603,18 @@ private static boolean isExecutableOrder(SettlementWorkOrder order) {
return false;
}
return switch (order.type()) {
- case HARVEST_CROP, BREAK_BLOCK, MINE_BLOCK, FELL_TREE, TILL_SOIL, PLANT_CROP, REPLANT_TREE, BUILD_BLOCK -> true;
+ case HARVEST_CROP,
+ BREAK_BLOCK,
+ MINE_BLOCK,
+ FELL_TREE,
+ FISH,
+ ANIMAL_BREED,
+ ANIMAL_SPECIAL_TASK,
+ ANIMAL_SLAUGHTER,
+ TILL_SOIL,
+ PLANT_CROP,
+ REPLANT_TREE,
+ BUILD_BLOCK -> true;
default -> false;
};
}
diff --git a/src/main/java/com/talhanation/bannermod/ai/military/AbstractRecruitObservedThreatGoal.java b/src/main/java/com/talhanation/bannermod/ai/military/AbstractRecruitObservedThreatGoal.java
index 2ff67741..6c5827f7 100644
--- a/src/main/java/com/talhanation/bannermod/ai/military/AbstractRecruitObservedThreatGoal.java
+++ b/src/main/java/com/talhanation/bannermod/ai/military/AbstractRecruitObservedThreatGoal.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod.ai.military;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.target.TargetGoal;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
diff --git a/src/main/java/com/talhanation/bannermod/ai/military/RecruitHoldPosGoal.java b/src/main/java/com/talhanation/bannermod/ai/military/RecruitHoldPosGoal.java
index 544797dc..acc05883 100644
--- a/src/main/java/com/talhanation/bannermod/ai/military/RecruitHoldPosGoal.java
+++ b/src/main/java/com/talhanation/bannermod/ai/military/RecruitHoldPosGoal.java
@@ -45,6 +45,12 @@ public boolean canContinueToUse() {
}
public void tick() {
+ LivingEntity leader = this.recruit.getOwner();
+ if (FormationDimensionGuard.shouldHoldDueToDimensionMismatch(this.recruit, leader)) {
+ this.recruit.getNavigation().stop();
+ return;
+ }
+
if (this.formationFallbackCooldown > 0) {
this.formationFallbackCooldown--;
}
@@ -86,10 +92,6 @@ private void tryGapFillScan() {
return;
}
// FORMATIONDIM-001: do not migrate formation slots while leader is in another dimension.
- LivingEntity leader = this.recruit.getOwner();
- if (FormationDimensionGuard.shouldHoldDueToDimensionMismatch(this.recruit, leader)) {
- return;
- }
CombatStance stance = this.recruit.getCombatStance();
if (!FormationGapFillPolicy.stanceAllowsGapFill(stance)) {
return;
diff --git a/src/main/java/com/talhanation/bannermod/events/ClaimEvent.java b/src/main/java/com/talhanation/bannermod/api/event/ClaimEvent.java
similarity index 98%
rename from src/main/java/com/talhanation/bannermod/events/ClaimEvent.java
rename to src/main/java/com/talhanation/bannermod/api/event/ClaimEvent.java
index 9c6c0738..089f2a39 100644
--- a/src/main/java/com/talhanation/bannermod/events/ClaimEvent.java
+++ b/src/main/java/com/talhanation/bannermod/api/event/ClaimEvent.java
@@ -1,4 +1,4 @@
-package com.talhanation.bannermod.events;
+package com.talhanation.bannermod.api.event;
import com.talhanation.bannermod.persistence.military.RecruitsClaim;
import net.minecraft.server.level.ServerLevel;
diff --git a/src/main/java/com/talhanation/bannermod/events/RecruitEvent.java b/src/main/java/com/talhanation/bannermod/api/event/RecruitEvent.java
similarity index 95%
rename from src/main/java/com/talhanation/bannermod/events/RecruitEvent.java
rename to src/main/java/com/talhanation/bannermod/api/event/RecruitEvent.java
index 1b3784a3..a1e6d7be 100644
--- a/src/main/java/com/talhanation/bannermod/events/RecruitEvent.java
+++ b/src/main/java/com/talhanation/bannermod/api/event/RecruitEvent.java
@@ -1,4 +1,4 @@
-package com.talhanation.bannermod.events;
+package com.talhanation.bannermod.api.event;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import net.minecraft.world.entity.player.Player;
@@ -110,7 +110,7 @@ public int getNewLevel() {
* Wird gefeuert, kurz bevor ein Recruit zu einem höheren Rang befördert wird.
*
Cancelable: {@code setCanceled(true)} verhindert die Beförderung.
*
- * @see RecruitEvents#promoteRecruit(AbstractRecruitEntity, int, String, net.minecraft.server.level.ServerPlayer)
+ * @see com.talhanation.bannermod.entity.military.runtime.RecruitEvents#promoteRecruit(AbstractRecruitEntity, int, String, net.minecraft.server.level.ServerPlayer)
*/
public static class Promoted extends RecruitEvent implements ICancellableEvent {
private final int newProfession;
diff --git a/src/main/java/com/talhanation/bannermod/army/command/RecruitCommandAuthority.java b/src/main/java/com/talhanation/bannermod/army/command/RecruitCommandAuthority.java
index a75a416e..3802aa9f 100644
--- a/src/main/java/com/talhanation/bannermod/army/command/RecruitCommandAuthority.java
+++ b/src/main/java/com/talhanation/bannermod/army/command/RecruitCommandAuthority.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod.army.command;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.persistence.military.RecruitsGroup;
import net.minecraft.server.level.ServerPlayer;
diff --git a/src/main/java/com/talhanation/bannermod/army/command/runtime/MovementFormationCommandService.java b/src/main/java/com/talhanation/bannermod/army/command/runtime/MovementFormationCommandService.java
index aa1eb373..42e48f03 100644
--- a/src/main/java/com/talhanation/bannermod/army/command/runtime/MovementFormationCommandService.java
+++ b/src/main/java/com/talhanation/bannermod/army/command/runtime/MovementFormationCommandService.java
@@ -7,7 +7,7 @@
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.entity.military.CaptainEntity;
import com.talhanation.bannermod.entity.military.RecruitIndex;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.persistence.military.RecruitsGroup;
import com.talhanation.bannermod.util.RuntimeProfilingCounters;
import com.talhanation.bannermod.util.FormationUtils;
diff --git a/src/main/java/com/talhanation/bannermod/bootstrap/BannerModMain.java b/src/main/java/com/talhanation/bannermod/bootstrap/BannerModMain.java
index 9b428cae..2e0b0313 100644
--- a/src/main/java/com/talhanation/bannermod/bootstrap/BannerModMain.java
+++ b/src/main/java/com/talhanation/bannermod/bootstrap/BannerModMain.java
@@ -6,7 +6,7 @@
import com.talhanation.bannermod.events.DamageEvent;
import com.talhanation.bannermod.events.PillagerEvents;
import com.talhanation.bannermod.events.RecruitCombatEvents;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.events.RecruitLifecycleEvents;
import com.talhanation.bannermod.events.VillagerEvents;
import com.talhanation.bannermod.events.WorkersVillagerEvents;
@@ -22,6 +22,7 @@
import com.talhanation.bannermod.compat.MedievalSiegeMachinesCompat;
import com.talhanation.bannermod.config.BannerModServerConfig;
import com.talhanation.bannermod.config.RecruitsClientConfig;
+import com.talhanation.bannermod.entity.military.perks.PerkReloadListener;
import com.talhanation.bannermod.war.config.WarServerConfig;
import com.talhanation.bannermod.war.events.WarPvpEvents;
import com.talhanation.bannermod.war.events.WarRevoltAutoResolver;
@@ -30,6 +31,7 @@
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
import net.neoforged.neoforge.common.NeoForge;
+import net.neoforged.neoforge.event.AddReloadListenerEvent;
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
import net.neoforged.neoforge.event.RegisterCommandsEvent;
import net.neoforged.bus.api.IEventBus;
@@ -75,6 +77,8 @@ public BannerModMain(IEventBus modEventBus, Dist dist, ModContainer modContainer
modEventBus.addListener(this::setup);
modEventBus.addListener(BannerModNetworkBootstrap::registerPayloads);
+ com.talhanation.bannermod.registry.ModAttachments.ATTACHMENT_TYPES.register(modEventBus);
+
// Register military deferred registers (from bannermod.registry.military)
com.talhanation.bannermod.registry.military.ModBlocks.BLOCKS.register(modEventBus);
com.talhanation.bannermod.registry.military.ModPois.POIS.register(modEventBus);
@@ -123,6 +127,11 @@ public void onRegisterCommands(RegisterCommandsEvent event) {
BannerModWarCommands.register(event.getDispatcher());
}
+ @SubscribeEvent
+ public void onAddReloadListeners(AddReloadListenerEvent event) {
+ event.addListener(new PerkReloadListener());
+ }
+
@SuppressWarnings({"unchecked", "rawtypes"})
private void setup(final FMLCommonSetupEvent event) {
// Workers runtime events
diff --git a/src/main/java/com/talhanation/bannermod/client/civilian/gui/CitizenProfileScreen.java b/src/main/java/com/talhanation/bannermod/client/civilian/gui/CitizenProfileScreen.java
index 2f32bfda..39b21c9e 100644
--- a/src/main/java/com/talhanation/bannermod/client/civilian/gui/CitizenProfileScreen.java
+++ b/src/main/java/com/talhanation/bannermod/client/civilian/gui/CitizenProfileScreen.java
@@ -1,12 +1,15 @@
package com.talhanation.bannermod.client.civilian.gui;
import com.talhanation.bannermod.client.military.ClientManager;
+import com.talhanation.bannermod.client.civilian.input.AssignHomeTargetSelector;
import com.talhanation.bannermod.client.military.gui.MilitaryGuiStyle;
import com.talhanation.bannermod.citizen.CitizenProfession;
import com.talhanation.bannermod.entity.citizen.CitizenEntity;
import com.talhanation.bannermod.inventory.civilian.CitizenProfileMenu;
import com.talhanation.bannermod.persistence.military.RecruitsPlayerInfo;
import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.client.gui.components.Button;
+import net.minecraft.client.gui.components.Tooltip;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.gui.screens.inventory.InventoryScreen;
import net.minecraft.network.chat.Component;
@@ -47,6 +50,16 @@ protected void init() {
}
}
).bounds(buttonX, buttonY, 134, 16).build());
+
+ Button assignHome = Button.builder(
+ Component.translatable("bannermod.assign_home.button"),
+ button -> {
+ AssignHomeTargetSelector.start(this.citizen.getUUID());
+ this.onClose();
+ }
+ ).bounds(this.leftPos + 14, this.topPos + 140, 70, 16).build();
+ assignHome.setTooltip(Tooltip.create(Component.translatable("bannermod.assign_home.tooltip")));
+ this.addRenderableWidget(assignHome);
}
@Override
diff --git a/src/main/java/com/talhanation/bannermod/client/civilian/gui/WorkerStatusScreen.java b/src/main/java/com/talhanation/bannermod/client/civilian/gui/WorkerStatusScreen.java
index 3d48883a..4c888225 100644
--- a/src/main/java/com/talhanation/bannermod/client/civilian/gui/WorkerStatusScreen.java
+++ b/src/main/java/com/talhanation/bannermod/client/civilian/gui/WorkerStatusScreen.java
@@ -3,11 +3,13 @@
import com.talhanation.bannermod.bootstrap.BannerModMain;
import com.talhanation.bannermod.citizen.CitizenProfession;
import com.talhanation.bannermod.citizen.CitizenRole;
+import com.talhanation.bannermod.client.civilian.input.AssignHomeTargetSelector;
import com.talhanation.bannermod.client.military.gui.MilitaryGuiStyle;
import com.talhanation.bannermod.client.military.gui.widgets.ActionMenuButton;
import com.talhanation.bannermod.client.military.gui.widgets.ContextMenuEntry;
import com.talhanation.bannermod.entity.civilian.WorkerInspectionSnapshot;
import com.talhanation.bannermod.network.messages.civilian.MessageConvertWorkerToCitizen;
+import com.talhanation.bannermod.network.messages.civilian.MessageDismissWorker;
import com.talhanation.bannermod.network.messages.civilian.MessageOpenWorkerScreen;
import com.talhanation.bannermod.network.messages.civilian.MessageReassignWorkerProfession;
import net.minecraft.client.Minecraft;
@@ -22,11 +24,11 @@
import java.util.Locale;
public class WorkerStatusScreen extends Screen {
- private static final int WIDTH = 252;
+ private static final int WIDTH = 300;
// 210 gives 22 px clearance between the bottom transport text box (ends at top+168)
// and the action button row (starts at top + HEIGHT - 26 = top+184) so they never overlap.
private static final int HEIGHT = 210;
- private static final int BTN_W = 58;
+ private static final int BTN_W = 54;
private static final int BTN_H = 20;
private final WorkerInspectionSnapshot snapshot;
@@ -44,10 +46,10 @@ protected void init() {
this.left = (this.width - WIDTH) / 2;
this.top = (this.height - HEIGHT) / 2;
- // Bottom action row: 4 evenly spaced buttons inside WIDTH.
- // Stride between centers = (WIDTH - 16) / 4 = 59 -> stays inside parchment frame.
+ // Bottom action row: 5 evenly spaced buttons inside WIDTH.
+ // Stride between centers = (WIDTH - 16) / 5 = 56 -> stays inside parchment frame.
int rowY = this.top + HEIGHT - 26;
- int strideX = (WIDTH - 16) / 4;
+ int strideX = (WIDTH - 16) / 5;
int firstCenter = this.left + 8 + strideX / 2;
SmallCommandButton refresh = this.addRenderableWidget(new SmallCommandButton(
@@ -57,20 +59,35 @@ protected void init() {
));
refresh.setTooltip(Tooltip.create(text("gui.bannermod.worker_screen.refresh.tooltip")));
- SmallCommandButton convert = this.addRenderableWidget(new SmallCommandButton(
- firstCenter + strideX - BTN_W / 2, rowY, BTN_W, BTN_H,
- clamped("gui.bannermod.worker_screen.convert"),
+ SmallCommandButton assignHome = this.addRenderableWidget(new SmallCommandButton(
+ firstCenter + 3 * strideX - BTN_W / 2, rowY, BTN_W, BTN_H,
+ clamped("bannermod.assign_home.button"),
button -> {
- BannerModMain.SIMPLE_CHANNEL.sendToServer(new MessageConvertWorkerToCitizen(this.snapshot.workerUuid()));
+ AssignHomeTargetSelector.start(this.snapshot.workerUuid());
this.onClose();
}
));
- convert.active = this.snapshot.canConvert();
+ assignHome.setTooltip(Tooltip.create(text("bannermod.assign_home.tooltip")));
+
+ SmallCommandButton close = this.addRenderableWidget(new SmallCommandButton(
+ firstCenter + 4 * strideX - BTN_W / 2, rowY, BTN_W, BTN_H,
+ clamped("gui.bannermod.worker_screen.close"),
+ button -> this.onClose()
+ ));
+ close.setTooltip(Tooltip.create(text("gui.bannermod.worker_screen.close.tooltip")));
+
+ ActionMenuButton workerActions = new ActionMenuButton(
+ firstCenter + strideX - BTN_W / 2, rowY, BTN_W, BTN_H,
+ clamped("gui.bannermod.worker_screen.actions"),
+ buildWorkerActionEntries()
+ );
+ workerActions.setOpenUpward(true);
if (this.snapshot.convertBlockedReasonKey() != null) {
- convert.setTooltip(Tooltip.create(text(this.snapshot.convertBlockedReasonKey())));
+ workerActions.setTooltip(Tooltip.create(text(this.snapshot.convertBlockedReasonKey())));
} else {
- convert.setTooltip(Tooltip.create(text("gui.bannermod.worker_screen.convert.tooltip.dismiss_path")));
+ workerActions.setTooltip(Tooltip.create(text("gui.bannermod.worker_screen.actions.tooltip")));
}
+ this.addRenderableWidget(workerActions);
// Reassign — opens an ActionMenuButton with one row per available
// CONTROLLED_WORKER profession (current one filtered out). Server is
@@ -84,13 +101,6 @@ protected void init() {
reassign.setTooltip(Tooltip.create(text("gui.bannermod.worker_screen.reassign.tooltip")));
reassign.active = this.snapshot.canConvert();
this.addRenderableWidget(reassign);
-
- SmallCommandButton close = this.addRenderableWidget(new SmallCommandButton(
- firstCenter + 3 * strideX - BTN_W / 2, rowY, BTN_W, BTN_H,
- clamped("gui.bannermod.worker_screen.close"),
- button -> this.onClose()
- ));
- close.setTooltip(Tooltip.create(text("gui.bannermod.worker_screen.close.tooltip")));
}
private List buildReassignEntries() {
@@ -116,6 +126,27 @@ private List buildReassignEntries() {
return entries;
}
+ private List buildWorkerActionEntries() {
+ List entries = new ArrayList<>();
+ entries.add(new ContextMenuEntry(
+ Component.translatable("gui.bannermod.worker_screen.convert").getString(),
+ () -> {
+ BannerModMain.SIMPLE_CHANNEL.sendToServer(new MessageConvertWorkerToCitizen(this.snapshot.workerUuid()));
+ this.onClose();
+ },
+ this.snapshot.canConvert()
+ ));
+ entries.add(new ContextMenuEntry(
+ Component.translatable("gui.bannermod.worker_screen.dismiss").getString(),
+ () -> {
+ BannerModMain.SIMPLE_CHANNEL.sendToServer(new MessageDismissWorker(this.snapshot.workerUuid()));
+ this.onClose();
+ },
+ true
+ ));
+ return entries;
+ }
+
@Override
public void renderBackground(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
super.renderBackground(graphics, mouseX, mouseY, partialTick);
@@ -179,7 +210,7 @@ public boolean isPauseScreen() {
/**
* Narrow command button styled with the same parchment-iron palette as
* {@link com.talhanation.bannermod.client.military.gui.group.RecruitsCommandButton}
- * but width-configurable so four widgets fit inside WIDTH=252.
+ * but width-configurable so the compact action row fits inside the ledger.
*/
private static class SmallCommandButton extends ExtendedButton {
SmallCommandButton(int x, int y, int width, int height, Component label, OnPress handler) {
diff --git a/src/main/java/com/talhanation/bannermod/client/civilian/input/AssignHomeTargetSelector.java b/src/main/java/com/talhanation/bannermod/client/civilian/input/AssignHomeTargetSelector.java
new file mode 100644
index 00000000..bfed7a09
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/client/civilian/input/AssignHomeTargetSelector.java
@@ -0,0 +1,100 @@
+package com.talhanation.bannermod.client.civilian.input;
+
+import com.talhanation.bannermod.bootstrap.BannerModMain;
+import com.talhanation.bannermod.client.military.gui.MilitaryGuiStyle;
+import com.talhanation.bannermod.network.messages.civilian.MessageAssignHome;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.Font;
+import net.minecraft.client.gui.GuiGraphics;
+import net.minecraft.core.BlockPos;
+import net.minecraft.network.chat.Component;
+import net.minecraft.world.phys.BlockHitResult;
+import net.minecraft.world.phys.HitResult;
+
+import java.util.UUID;
+
+public final class AssignHomeTargetSelector {
+ private static final long TIMEOUT_MS = 30_000L;
+ private static final int PANEL_WIDTH = 214;
+ private static final int PANEL_HEIGHT = 30;
+ private static final int RIGHT_SAFE_MARGIN = 8;
+
+ private static UUID entityUuid;
+ private static long startedAtMs;
+
+ private AssignHomeTargetSelector() {
+ }
+
+ public static void start(UUID targetEntityUuid) {
+ entityUuid = targetEntityUuid;
+ startedAtMs = System.currentTimeMillis();
+ Minecraft mc = Minecraft.getInstance();
+ if (mc.player != null) {
+ mc.player.displayClientMessage(Component.translatable("bannermod.assign_home.prompt"), true);
+ }
+ }
+
+ public static boolean isActive() {
+ return entityUuid != null;
+ }
+
+ public static void reset() {
+ clear();
+ }
+
+ public static void tick() {
+ if (!isActive()) return;
+ if (System.currentTimeMillis() - startedAtMs >= TIMEOUT_MS) {
+ cancel("bannermod.assign_home.cancel.timeout");
+ }
+ }
+
+ public static boolean cancelWithEscape() {
+ if (!isActive()) return false;
+ cancel("bannermod.assign_home.cancel.escape");
+ return true;
+ }
+
+ public static boolean handleUseOnTargetedBlock() {
+ if (!isActive()) return false;
+ Minecraft mc = Minecraft.getInstance();
+ if (!(mc.hitResult instanceof BlockHitResult hit) || mc.hitResult.getType() != HitResult.Type.BLOCK) {
+ return false;
+ }
+ UUID uuid = entityUuid;
+ BlockPos pos = hit.getBlockPos().immutable();
+ clear();
+ BannerModMain.SIMPLE_CHANNEL.sendToServer(new MessageAssignHome(uuid, pos));
+ return true;
+ }
+
+ public static int renderPrompt(GuiGraphics graphics, Minecraft mc, int y) {
+ if (!isActive() || mc.player == null) return y;
+ Font font = mc.font;
+ int x = Math.max(6, graphics.guiWidth() - PANEL_WIDTH - RIGHT_SAFE_MARGIN);
+ MilitaryGuiStyle.parchmentPanel(graphics, x, y, PANEL_WIDTH, PANEL_HEIGHT);
+ graphics.drawString(font, Component.translatable("bannermod.assign_home.hud.title"), x + 8, y + 6,
+ MilitaryGuiStyle.TEXT_DARK, false);
+ graphics.drawString(font, Component.translatable("bannermod.assign_home.hud.remaining", remainingSeconds()),
+ x + 8, y + 18, MilitaryGuiStyle.TEXT_MUTED, false);
+ return y + PANEL_HEIGHT + 4;
+ }
+
+ private static int remainingSeconds() {
+ long remainingMs = Math.max(0L, TIMEOUT_MS - (System.currentTimeMillis() - startedAtMs));
+ return (int) Math.ceil(remainingMs / 1000.0D);
+ }
+
+ private static void cancel(String messageKey) {
+ clear();
+ Minecraft mc = Minecraft.getInstance();
+ if (mc.player != null) {
+ mc.player.displayClientMessage(Component.translatable(messageKey), true);
+ }
+ }
+
+ private static void clear() {
+ entityUuid = null;
+ startedAtMs = 0L;
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/client/military/events/ClientPlayerEvents.java b/src/main/java/com/talhanation/bannermod/client/military/events/ClientPlayerEvents.java
index 1640c43b..1ac246d2 100644
--- a/src/main/java/com/talhanation/bannermod/client/military/events/ClientPlayerEvents.java
+++ b/src/main/java/com/talhanation/bannermod/client/military/events/ClientPlayerEvents.java
@@ -1,5 +1,6 @@
package com.talhanation.bannermod.client.military.events;
+import com.talhanation.bannermod.client.civilian.input.AssignHomeTargetSelector;
import com.talhanation.bannermod.client.military.gui.worldmap.ChunkTileManager;
import com.talhanation.bannermod.client.military.gui.worldmap.WorldMapScreen;
import com.talhanation.bannermod.config.RecruitsClientConfig;
@@ -12,6 +13,8 @@
public class ClientPlayerEvents {
@SubscribeEvent
public void onClientTick(ClientTickEvent.Post event) {
+ AssignHomeTargetSelector.tick();
+
if (!(Minecraft.getInstance().screen instanceof WorldMapScreen screen)) return;
if (!RecruitsClientConfig.UpdateMapTiles.get()) return;
@@ -36,6 +39,7 @@ public void onWorldLoad(LevelEvent.Load event) {
@SubscribeEvent
public void onWorldUnload(LevelEvent.Unload event) {
if (event.getLevel().isClientSide()) {
+ AssignHomeTargetSelector.reset();
ChunkTileManager.getInstance().close();
}
}
diff --git a/src/main/java/com/talhanation/bannermod/client/military/events/KeyEvents.java b/src/main/java/com/talhanation/bannermod/client/military/events/KeyEvents.java
index b6beb612..7413dd5a 100644
--- a/src/main/java/com/talhanation/bannermod/client/military/events/KeyEvents.java
+++ b/src/main/java/com/talhanation/bannermod/client/military/events/KeyEvents.java
@@ -3,6 +3,7 @@
import com.talhanation.bannermod.events.CommandEvents;
import com.talhanation.bannermod.bootstrap.BannerModMain;
import com.talhanation.bannermod.client.civilian.gui.WorkerCommandScreen;
+import com.talhanation.bannermod.client.civilian.input.AssignHomeTargetSelector;
import com.talhanation.bannermod.client.civilian.render.WorkerAreaRenderer;
import com.talhanation.bannermod.client.military.gui.war.WarListScreen;
import com.talhanation.bannermod.client.military.gui.worldmap.WorldMapScreen;
@@ -21,6 +22,7 @@
import net.neoforged.api.distmarker.OnlyIn;
import net.neoforged.neoforge.client.event.InputEvent;
import net.neoforged.bus.api.SubscribeEvent;
+import org.lwjgl.glfw.GLFW;
@OnlyIn(Dist.CLIENT)
@@ -32,6 +34,11 @@ public void onKeyInput(InputEvent.Key event) {
if (clientPlayerEntity == null)
return;
+ if (event.getKey() == GLFW.GLFW_KEY_ESCAPE && event.getAction() == GLFW.GLFW_PRESS
+ && AssignHomeTargetSelector.cancelWithEscape()) {
+ return;
+ }
+
if (ModShortcuts.COMMAND_SCREEN_KEY != null && ModShortcuts.COMMAND_SCREEN_KEY.consumeClick()) {
CommandEvents.openCommandScreen(clientPlayerEntity);
}
@@ -70,6 +77,11 @@ public void onKeyInput(InputEvent.Key event) {
@SubscribeEvent
public void onPlayerPick(InputEvent.InteractionKeyMappingTriggered event){
+ if (event.isUseItem() && AssignHomeTargetSelector.handleUseOnTargetedBlock()) {
+ event.setCanceled(true);
+ return;
+ }
+
if(event.isPickBlock()){
Minecraft minecraft = Minecraft.getInstance();
LocalPlayer clientPlayerEntity = minecraft.player;
diff --git a/src/main/java/com/talhanation/bannermod/client/military/gui/RecruitInventoryScreen.java b/src/main/java/com/talhanation/bannermod/client/military/gui/RecruitInventoryScreen.java
index 6d5aa0ee..82f527b8 100644
--- a/src/main/java/com/talhanation/bannermod/client/military/gui/RecruitInventoryScreen.java
+++ b/src/main/java/com/talhanation/bannermod/client/military/gui/RecruitInventoryScreen.java
@@ -3,7 +3,8 @@
import com.mojang.blaze3d.systems.RenderSystem;
import com.talhanation.bannermod.ai.military.CombatStance;
import com.talhanation.bannermod.bootstrap.BannerModMain;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.client.civilian.input.AssignHomeTargetSelector;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.client.military.ClientManager;
import com.talhanation.bannermod.client.military.gui.widgets.ActionMenuButton;
import com.talhanation.bannermod.client.military.gui.widgets.ContextMenuEntry;
@@ -110,6 +111,8 @@ public class RecruitInventoryScreen extends ScreenBase {
private static final MutableComponent TEXT_MENU_AGGRO = Component.translatable("gui.recruits.command.menu.aggro");
private static final MutableComponent TEXT_MENU_ORDERS = Component.translatable("gui.recruits.inv.menu.orders");
private static final MutableComponent TEXT_MENU_MOUNT = Component.translatable("gui.recruits.inv.menu.mount");
+ private static final MutableComponent TEXT_ASSIGN_HOME = Component.translatable("bannermod.assign_home.button");
+ private static final MutableComponent TOOLTIP_ASSIGN_HOME = Component.translatable("bannermod.assign_home.tooltip");
private static final MutableComponent STATUS_READ_ONLY = Component.translatable("gui.recruits.inv.status.read_only");
private static final MutableComponent STATUS_GROUP_UNSET = Component.translatable("gui.recruits.inv.status.group_unset");
private static final MutableComponent STATUS_GROUP_LOCKED = Component.translatable("gui.recruits.inv.status.group_locked");
@@ -310,6 +313,13 @@ protected void init() {
if (!moreButton.active) moreButton.setTooltip(Tooltip.create(TOOLTIP_NOBLE_LOCKED));
addRenderableWidget(moreButton);
+ Button assignHome = addRenderableWidget(new ProfileButton(zeroLeftPos, zeroTopPos + (20 + topPosGab) * 6,
+ 80, 20, TEXT_ASSIGN_HOME, button -> {
+ AssignHomeTargetSelector.start(this.recruit.getUUID());
+ this.onClose();
+ }));
+ assignHome.setTooltip(Tooltip.create(TOOLTIP_ASSIGN_HOME));
+
if(recruit instanceof VillagerNobleEntity){
return;
}
diff --git a/src/main/java/com/talhanation/bannermod/client/military/gui/overlay/HudOverlayCoordinator.java b/src/main/java/com/talhanation/bannermod/client/military/gui/overlay/HudOverlayCoordinator.java
index 53734872..fc6ee29d 100644
--- a/src/main/java/com/talhanation/bannermod/client/military/gui/overlay/HudOverlayCoordinator.java
+++ b/src/main/java/com/talhanation/bannermod/client/military/gui/overlay/HudOverlayCoordinator.java
@@ -1,6 +1,7 @@
package com.talhanation.bannermod.client.military.gui.overlay;
import com.talhanation.bannermod.bootstrap.BannerModMain;
+import com.talhanation.bannermod.client.civilian.input.AssignHomeTargetSelector;
import com.talhanation.bannermod.client.military.ClientManager;
import com.talhanation.bannermod.client.military.api.ClientClaimEvent;
import com.talhanation.bannermod.client.military.api.ClientOverlayEvent;
@@ -124,7 +125,7 @@ private void renderOverlays(GuiGraphics graphics) {
if (mc.player == null || mc.level == null) return;
if (mc.options.hideGui || mc.getDebugOverlay().showDebugScreen() || mc.options.keyPlayerList.isDown()) return;
- int y = TOP_SAFE_MARGIN;
+ int y = AssignHomeTargetSelector.renderPrompt(graphics, mc, TOP_SAFE_MARGIN);
y = renderBattleWindow(graphics, mc, y);
y = renderSiegeZone(graphics, mc, y);
renderClaim(graphics, mc, y);
diff --git a/src/main/java/com/talhanation/bannermod/client/settlement/BannerModSettlementClientMirror.java b/src/main/java/com/talhanation/bannermod/client/settlement/BannerModSettlementClientMirror.java
index 1df7265b..ec4f4e97 100644
--- a/src/main/java/com/talhanation/bannermod/client/settlement/BannerModSettlementClientMirror.java
+++ b/src/main/java/com/talhanation/bannermod/client/settlement/BannerModSettlementClientMirror.java
@@ -3,9 +3,9 @@
import com.talhanation.bannermod.governance.BannerModGovernorPolicy;
import com.talhanation.bannermod.governance.BannerModGovernorRecommendation;
import com.talhanation.bannermod.governance.BannerModGovernorSnapshot;
-import com.talhanation.bannermod.settlement.BannerModSettlementDesiredGoodSeed;
-import com.talhanation.bannermod.settlement.BannerModSettlementSnapshot;
-import com.talhanation.bannermod.settlement.BannerModSettlementStrategicSignals;
+import com.talhanation.bannermod.settlement.SettlementDesiredGoodSnapshot;
+import com.talhanation.bannermod.settlement.SettlementSnapshot;
+import com.talhanation.bannermod.settlement.SettlementStrategicSignals;
import com.talhanation.bannermod.shared.settlement.BannerModSettlementClientSnapshotContract.Envelope;
import com.talhanation.bannermod.shared.settlement.BannerModSettlementClientSnapshotContract.Payload;
import com.talhanation.bannermod.shared.settlement.BannerModSettlementClientSnapshotContract.RefreshTrigger;
@@ -52,13 +52,13 @@ public GovernorView governorView(UUID recruitId) {
}
Payload payload = envelope.payload();
- BannerModSettlementSnapshot settlement = payload.settlementSnapshot();
+ SettlementSnapshot settlement = payload.settlementSnapshot();
BannerModGovernorSnapshot governor = payload.governorSnapshot();
boolean stale = envelope.isStale();
List recommendations = governor == null ? List.of() : new ArrayList<>(governor.recommendationTokens());
if (settlement != null) {
recommendations = new ArrayList<>(recommendations);
- recommendations.addAll(settlement.tradeRouteHandoffSeed().seaTradeStatusLines());
+ recommendations.addAll(settlement.tradeRouteHandoffSnapshot().seaTradeStatusLines());
}
return new GovernorView(
@@ -88,7 +88,7 @@ public GovernorView governorView(UUID recruitId) {
);
}
- private static List buildLogisticsLines(@Nullable BannerModSettlementSnapshot settlement) {
+ private static List buildLogisticsLines(@Nullable SettlementSnapshot settlement) {
if (settlement == null) {
return List.of("gui.bannermod.governor.logistics.none");
}
@@ -101,13 +101,13 @@ private static List buildLogisticsLines(@Nullable BannerModSettlementSna
lines.add("gui.bannermod.governor.logistics.stockpile "
+ settlement.stockpileSummary().containerCount() + " "
+ settlement.stockpileSummary().slotCapacity());
- BannerModSettlementStrategicSignals signals = BannerModSettlementStrategicSignals.fromSnapshot(settlement);
+ SettlementStrategicSignals signals = SettlementStrategicSignals.fromSnapshot(settlement);
lines.add("gui.bannermod.governor.logistics.role " + signals.roleId());
- List desiredGoods = settlement.desiredGoodsSeed().desiredGoods();
+ List desiredGoods = settlement.desiredGoodsSnapshot().desiredGoods();
lines.add(desiredGoods.isEmpty()
? "gui.bannermod.governor.logistics.goods_none"
: "gui.bannermod.governor.logistics.goods " + desiredGoods.get(0).desiredGoodId() + " " + desiredGoods.get(0).driverCount());
- lines.addAll(settlement.tradeRouteHandoffSeed().seaTradeStatusLines());
+ lines.addAll(settlement.tradeRouteHandoffSnapshot().seaTradeStatusLines());
return lines;
}
diff --git a/src/main/java/com/talhanation/bannermod/commands/admin/AdminDebugCommands.java b/src/main/java/com/talhanation/bannermod/commands/admin/AdminDebugCommands.java
new file mode 100644
index 00000000..a046d4b5
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/commands/admin/AdminDebugCommands.java
@@ -0,0 +1,192 @@
+package com.talhanation.bannermod.commands.admin;
+
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.talhanation.bannermod.ai.pathfinding.GlobalPathfindingController;
+import com.talhanation.bannermod.entity.civilian.WorkerIndex;
+import com.talhanation.bannermod.entity.civilian.workarea.AbstractWorkAreaEntity;
+import com.talhanation.bannermod.entity.civilian.workarea.WorkAreaIndex;
+import com.talhanation.bannermod.entity.military.RecruitIndex;
+import com.talhanation.bannermod.governance.BannerModGovernorManager;
+import com.talhanation.bannermod.governance.BannerModTreasuryManager;
+import com.talhanation.bannermod.persistence.military.RecruitPlayerUnitSaveData;
+import com.talhanation.bannermod.persistence.military.RecruitsClaimSaveData;
+import com.talhanation.bannermod.persistence.military.RecruitsGroupsSaveData;
+import com.talhanation.bannermod.settlement.SettlementManager;
+import com.talhanation.bannermod.settlement.bootstrap.SettlementRegistryData;
+import com.talhanation.bannermod.settlement.building.ValidatedBuildingRegistryData;
+import com.talhanation.bannermod.settlement.dispatch.BannerModSellerDispatchSavedData;
+import com.talhanation.bannermod.settlement.household.BannerModHomeAssignmentSavedData;
+import com.talhanation.bannermod.settlement.prefab.player.PlayerBuildingRegistrySavedData;
+import com.talhanation.bannermod.settlement.project.SettlementProjectSavedData;
+import com.talhanation.bannermod.settlement.validation.BuildingInvalidationQueueData;
+import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrderSavedData;
+import com.talhanation.bannermod.shared.logistics.BannerModSeaTradeExecutionSavedData;
+import com.talhanation.bannermod.util.RuntimeProfilingCounters;
+import com.talhanation.bannermod.war.audit.WarAuditLogSavedData;
+import com.talhanation.bannermod.war.cooldown.WarCooldownSavedData;
+import com.talhanation.bannermod.war.registry.WarPoliticalRegistrySavedData;
+import com.talhanation.bannermod.war.runtime.DemilitarizationSavedData;
+import com.talhanation.bannermod.war.runtime.OccupationSavedData;
+import com.talhanation.bannermod.war.runtime.RevoltSavedData;
+import com.talhanation.bannermod.war.runtime.SiegeStandardSavedData;
+import com.talhanation.bannermod.war.runtime.WarAllyInviteSavedData;
+import com.talhanation.bannermod.war.runtime.WarDeclarationSavedData;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.commands.Commands;
+import net.minecraft.network.chat.Component;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.level.ChunkPos;
+
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Map;
+
+public final class AdminDebugCommands {
+ private static final SimpleCommandExceptionType INVALID_CHUNK = new SimpleCommandExceptionType(
+ Component.literal("chunk must be formatted as x,z")
+ );
+ private static final SimpleCommandExceptionType SERVER_ONLY = new SimpleCommandExceptionType(
+ Component.literal("This command can only run on a server")
+ );
+ private static final List> VERSIONED_SAVED_DATA = List.of(
+ RecruitsClaimSaveData.class,
+ RecruitsGroupsSaveData.class,
+ RecruitPlayerUnitSaveData.class,
+ BannerModSeaTradeExecutionSavedData.class,
+ WarPoliticalRegistrySavedData.class,
+ WarCooldownSavedData.class,
+ WarAllyInviteSavedData.class,
+ OccupationSavedData.class,
+ RevoltSavedData.class,
+ DemilitarizationSavedData.class,
+ SiegeStandardSavedData.class,
+ WarDeclarationSavedData.class,
+ WarAuditLogSavedData.class,
+ BannerModGovernorManager.class,
+ BannerModTreasuryManager.class,
+ BannerModSellerDispatchSavedData.class,
+ SettlementWorkOrderSavedData.class,
+ BannerModHomeAssignmentSavedData.class,
+ SettlementManager.class,
+ SettlementRegistryData.class,
+ BuildingInvalidationQueueData.class,
+ ValidatedBuildingRegistryData.class,
+ SettlementProjectSavedData.class,
+ PlayerBuildingRegistrySavedData.class
+ );
+
+ private AdminDebugCommands() {
+ }
+
+ public static LiteralArgumentBuilder debug() {
+ return Commands.literal("debug")
+ .requires(source -> source.hasPermission(2))
+ .then(Commands.literal("index")
+ .then(indexTarget("recruits"))
+ .then(indexTarget("workers"))
+ .then(indexTarget("workareas")))
+ .then(Commands.literal("pathfinding")
+ .then(Commands.literal("stats")
+ .executes(AdminDebugCommands::pathfindingStats)))
+ .then(Commands.literal("counters")
+ .then(Commands.literal("dump")
+ .executes(AdminDebugCommands::countersDump)))
+ .then(Commands.literal("save-versions")
+ .executes(AdminDebugCommands::saveVersions));
+ }
+
+ private static LiteralArgumentBuilder indexTarget(String type) {
+ return Commands.literal(type)
+ .then(Commands.argument("chunk", StringArgumentType.greedyString())
+ .executes(context -> index(context, type)));
+ }
+
+ private static int index(CommandContext context, String type) throws CommandSyntaxException {
+ ServerLevel level = serverLevel(context.getSource());
+ ChunkPos chunk = parseChunk(StringArgumentType.getString(context, "chunk"));
+ int count = switch (type) {
+ case "recruits" -> RecruitIndex.instance().countInChunk(level, chunk, true);
+ case "workers" -> WorkerIndex.instance().countInChunk(level, chunk, true);
+ case "workareas" -> WorkAreaIndex.instance().countInChunk(level, chunk, AbstractWorkAreaEntity.class);
+ default -> throw new IllegalArgumentException("Unknown index type: " + type);
+ };
+ context.getSource().sendSuccess(() -> Component.literal(
+ "Index " + type + " chunk " + chunk.x + "," + chunk.z + ": " + count
+ ), false);
+ return count;
+ }
+
+ private static int pathfindingStats(CommandContext context) throws CommandSyntaxException {
+ serverLevel(context.getSource());
+ GlobalPathfindingController.ProfilingSnapshot snapshot = GlobalPathfindingController.profilingSnapshot();
+ context.getSource().sendSuccess(() -> Component.literal(
+ "Pathfinding stats: requests=" + snapshot.totalRequests()
+ + " executedBudget=" + snapshot.budgetUsedThisTick() + "/" + snapshot.requestBudgetPerTick()
+ + " deferredQueue=" + snapshot.currentDeferredQueueDepth()
+ + " maxDeferredQueue=" + snapshot.maxDeferredQueueDepth()
+ ), false);
+ return 1;
+ }
+
+ private static int countersDump(CommandContext context) throws CommandSyntaxException {
+ serverLevel(context.getSource());
+ Map snapshot = RuntimeProfilingCounters.snapshot();
+ if (snapshot.isEmpty()) {
+ context.getSource().sendSuccess(() -> Component.literal("No runtime counters recorded."), false);
+ return 1;
+ }
+ for (Map.Entry entry : snapshot.entrySet()) {
+ context.getSource().sendSuccess(() -> Component.literal(entry.getKey() + "=" + entry.getValue()), false);
+ }
+ return snapshot.size();
+ }
+
+ private static int saveVersions(CommandContext context) throws CommandSyntaxException {
+ serverLevel(context.getSource());
+ int reported = 0;
+ for (Class> savedDataClass : VERSIONED_SAVED_DATA) {
+ Integer version = currentVersion(savedDataClass);
+ if (version == null) {
+ context.getSource().sendSuccess(() -> Component.literal(savedDataClass.getSimpleName() + "=unavailable"), false);
+ continue;
+ }
+ reported++;
+ context.getSource().sendSuccess(() -> Component.literal(savedDataClass.getSimpleName() + "=" + version), false);
+ }
+ return reported;
+ }
+
+ private static Integer currentVersion(Class> savedDataClass) {
+ try {
+ Field field = savedDataClass.getDeclaredField("CURRENT_VERSION");
+ field.setAccessible(true);
+ return field.getInt(null);
+ } catch (ReflectiveOperationException | RuntimeException exception) {
+ return null;
+ }
+ }
+
+ private static ChunkPos parseChunk(String value) throws CommandSyntaxException {
+ String[] parts = value.split(",", -1);
+ if (parts.length != 2) {
+ throw INVALID_CHUNK.create();
+ }
+ try {
+ return new ChunkPos(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]));
+ } catch (NumberFormatException exception) {
+ throw INVALID_CHUNK.create();
+ }
+ }
+
+ private static ServerLevel serverLevel(CommandSourceStack source) throws CommandSyntaxException {
+ ServerLevel level = source.getLevel();
+ if (level == null || level.isClientSide()) {
+ throw SERVER_ONLY.create();
+ }
+ return level;
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/commands/admin/AdminRecoveryCommands.java b/src/main/java/com/talhanation/bannermod/commands/admin/AdminRecoveryCommands.java
new file mode 100644
index 00000000..046f86ab
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/commands/admin/AdminRecoveryCommands.java
@@ -0,0 +1,212 @@
+package com.talhanation.bannermod.commands.admin;
+
+import com.mojang.brigadier.arguments.IntegerArgumentType;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
+import com.talhanation.bannermod.entity.civilian.AbstractWorkerEntity;
+import com.talhanation.bannermod.events.ClaimEvents;
+import com.talhanation.bannermod.governance.BannerModTreasuryLedgerSnapshot;
+import com.talhanation.bannermod.governance.BannerModTreasuryManager;
+import com.talhanation.bannermod.persistence.military.RecruitsClaim;
+import com.talhanation.bannermod.persistence.military.RecruitsPlayerInfo;
+import com.talhanation.bannermod.settlement.SettlementManager;
+import net.minecraft.core.BlockPos;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.commands.Commands;
+import net.minecraft.network.chat.Component;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.phys.AABB;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+public final class AdminRecoveryCommands {
+ private static final SimpleCommandExceptionType INVALID_UUID = new SimpleCommandExceptionType(
+ Component.literal("claimUuid must be a valid UUID")
+ );
+ private static final SimpleCommandExceptionType SERVER_ONLY = new SimpleCommandExceptionType(
+ Component.literal("This command can only run on a server")
+ );
+ private static final SimpleCommandExceptionType WORKER_NOT_FOUND = new SimpleCommandExceptionType(
+ Component.literal("entityId must reference a loaded worker")
+ );
+ private static final SimpleCommandExceptionType CHUNK_NOT_LOADED = new SimpleCommandExceptionType(
+ Component.literal("chunk must be loaded")
+ );
+ private static final SimpleCommandExceptionType NO_WORKERS_IN_CHUNK = new SimpleCommandExceptionType(
+ Component.literal("chunk must contain at least one loaded worker")
+ );
+
+ private AdminRecoveryCommands() {
+ }
+
+ public static LiteralArgumentBuilder settlement() {
+ return Commands.literal("settlement")
+ .requires(source -> source.hasPermission(2))
+ .then(Commands.literal("prune")
+ .then(Commands.argument("claimUuid", StringArgumentType.word())
+ .executes(AdminRecoveryCommands::pruneSettlement)));
+ }
+
+ public static LiteralArgumentBuilder treasury() {
+ return Commands.literal("treasury")
+ .requires(source -> source.hasPermission(2))
+ .then(Commands.literal("set")
+ .then(Commands.argument("claimUuid", StringArgumentType.word())
+ .then(Commands.argument("amount", IntegerArgumentType.integer(0))
+ .executes(AdminRecoveryCommands::setTreasury))))
+ .then(Commands.literal("show")
+ .then(Commands.argument("claimUuid", StringArgumentType.word())
+ .executes(AdminRecoveryCommands::showTreasury)));
+ }
+
+ public static LiteralArgumentBuilder claim() {
+ return Commands.literal("claim")
+ .requires(source -> source.hasPermission(2))
+ .then(Commands.literal("trust")
+ .then(Commands.literal("prune-dead-uuids")
+ .executes(AdminRecoveryCommands::pruneDeadTrustedUuids)));
+ }
+
+ public static LiteralArgumentBuilder worker() {
+ return Commands.literal("worker")
+ .requires(source -> source.hasPermission(2))
+ .then(Commands.literal("unbind")
+ .then(Commands.argument("entityId", IntegerArgumentType.integer(0))
+ .executes(AdminRecoveryCommands::unbindWorker)))
+ .then(Commands.literal("rehome")
+ .then(Commands.argument("chunkX", IntegerArgumentType.integer())
+ .then(Commands.argument("chunkZ", IntegerArgumentType.integer())
+ .executes(AdminRecoveryCommands::rehomeWorkers))));
+ }
+
+ private static int pruneSettlement(CommandContext context) throws CommandSyntaxException {
+ ServerLevel level = serverLevel(context.getSource());
+ UUID claimUuid = claimUuid(context);
+ boolean removed = SettlementManager.get(level).removeSnapshot(claimUuid) != null;
+ context.getSource().sendSuccess(() -> Component.literal(
+ removed ? "Pruned settlement snapshot " + claimUuid : "No settlement snapshot found for " + claimUuid
+ ), false);
+ return removed ? 1 : 0;
+ }
+
+ private static int setTreasury(CommandContext context) throws CommandSyntaxException {
+ ServerLevel level = serverLevel(context.getSource());
+ UUID claimUuid = claimUuid(context);
+ int amount = IntegerArgumentType.getInteger(context, "amount");
+ BannerModTreasuryManager treasury = BannerModTreasuryManager.get(level);
+ BannerModTreasuryLedgerSnapshot previous = treasury.getLedger(claimUuid);
+ ChunkPos anchor = previous == null ? new ChunkPos(0, 0) : previous.anchorChunk();
+ String settlementFactionId = previous == null ? null : previous.settlementFactionId();
+ treasury.putLedger(new BannerModTreasuryLedgerSnapshot(
+ claimUuid,
+ anchor.x,
+ anchor.z,
+ settlementFactionId,
+ amount,
+ 0,
+ amount,
+ level.getGameTime(),
+ 0,
+ 0L
+ ));
+ context.getSource().sendSuccess(() -> Component.literal("Treasury " + claimUuid + " set to " + amount), false);
+ return 1;
+ }
+
+ private static int showTreasury(CommandContext context) throws CommandSyntaxException {
+ ServerLevel level = serverLevel(context.getSource());
+ UUID claimUuid = claimUuid(context);
+ BannerModTreasuryLedgerSnapshot ledger = BannerModTreasuryManager.get(level).getLedger(claimUuid);
+ int amount = ledger == null ? 0 : ledger.treasuryBalance();
+ context.getSource().sendSuccess(() -> Component.literal("Treasury " + claimUuid + " balance: " + amount), false);
+ return 1;
+ }
+
+ private static int pruneDeadTrustedUuids(CommandContext context) throws CommandSyntaxException {
+ ServerLevel level = serverLevel(context.getSource());
+ int removed = 0;
+ for (RecruitsClaim claim : ClaimEvents.claimManager().getAllClaims()) {
+ List trustedPlayers = claim.getTrustedPlayers();
+ List pruned = new ArrayList<>();
+ Set seen = new LinkedHashSet<>();
+ for (RecruitsPlayerInfo trustedPlayer : trustedPlayers) {
+ if (trustedPlayer == null || trustedPlayer.getUUID() == null || !seen.add(trustedPlayer.getUUID())) {
+ removed++;
+ continue;
+ }
+ pruned.add(trustedPlayer);
+ }
+ if (pruned.size() != trustedPlayers.size()) {
+ claim.setTrustedPlayers(pruned);
+ ClaimEvents.claimManager().addOrUpdateClaim(level, claim);
+ }
+ }
+ int removedCount = removed;
+ context.getSource().sendSuccess(() -> Component.literal("Pruned " + removedCount + " dead trusted UUID entries"), false);
+ return removed;
+ }
+
+ private static int unbindWorker(CommandContext context) throws CommandSyntaxException {
+ ServerLevel level = serverLevel(context.getSource());
+ int entityId = IntegerArgumentType.getInteger(context, "entityId");
+ Entity entity = level.getEntity(entityId);
+ if (!(entity instanceof AbstractWorkerEntity worker)) {
+ throw WORKER_NOT_FOUND.create();
+ }
+ worker.setCurrentWorkArea(null);
+ context.getSource().sendSuccess(() -> Component.literal("Unbound worker " + entityId), false);
+ return 1;
+ }
+
+ private static int rehomeWorkers(CommandContext context) throws CommandSyntaxException {
+ ServerLevel level = serverLevel(context.getSource());
+ int chunkX = IntegerArgumentType.getInteger(context, "chunkX");
+ int chunkZ = IntegerArgumentType.getInteger(context, "chunkZ");
+ if (!level.hasChunk(chunkX, chunkZ)) {
+ throw CHUNK_NOT_LOADED.create();
+ }
+
+ ChunkPos chunk = new ChunkPos(chunkX, chunkZ);
+ BlockPos home = new BlockPos(chunk.getMiddleBlockX(), level.getSeaLevel(), chunk.getMiddleBlockZ());
+ AABB chunkBounds = new AABB(
+ chunk.getMinBlockX(), level.getMinBuildHeight(), chunk.getMinBlockZ(),
+ chunk.getMaxBlockX() + 1, level.getMaxBuildHeight(), chunk.getMaxBlockZ() + 1
+ );
+ List workers = level.getEntitiesOfClass(AbstractWorkerEntity.class, chunkBounds);
+ if (workers.isEmpty()) {
+ throw NO_WORKERS_IN_CHUNK.create();
+ }
+ for (AbstractWorkerEntity worker : workers) {
+ worker.setHomePos(home);
+ worker.setHomeBuildAreaUUID(null);
+ }
+ int count = workers.size();
+ context.getSource().sendSuccess(() -> Component.literal("Rehomed " + count + " worker(s) to chunk " + chunkX + "," + chunkZ), false);
+ return count;
+ }
+
+ private static UUID claimUuid(CommandContext context) throws CommandSyntaxException {
+ try {
+ return UUID.fromString(StringArgumentType.getString(context, "claimUuid"));
+ } catch (IllegalArgumentException exception) {
+ throw INVALID_UUID.create();
+ }
+ }
+
+ private static ServerLevel serverLevel(CommandSourceStack source) throws CommandSyntaxException {
+ ServerLevel level = source.getLevel();
+ if (level == null || level.isClientSide()) {
+ throw SERVER_ONLY.create();
+ }
+ return level;
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/commands/military/UnitsManagerAdminCommands.java b/src/main/java/com/talhanation/bannermod/commands/military/UnitsManagerAdminCommands.java
index 2134144b..a3fec108 100644
--- a/src/main/java/com/talhanation/bannermod/commands/military/UnitsManagerAdminCommands.java
+++ b/src/main/java/com/talhanation/bannermod/commands/military/UnitsManagerAdminCommands.java
@@ -5,7 +5,7 @@
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.talhanation.bannermod.config.RecruitsServerConfig;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import net.minecraft.ChatFormatting;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
diff --git a/src/main/java/com/talhanation/bannermod/commands/war/BannerModWarCommands.java b/src/main/java/com/talhanation/bannermod/commands/war/BannerModWarCommands.java
index 76acc638..b34f8788 100644
--- a/src/main/java/com/talhanation/bannermod/commands/war/BannerModWarCommands.java
+++ b/src/main/java/com/talhanation/bannermod/commands/war/BannerModWarCommands.java
@@ -2,6 +2,8 @@
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.talhanation.bannermod.commands.admin.AdminDebugCommands;
+import com.talhanation.bannermod.commands.admin.AdminRecoveryCommands;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
@@ -15,6 +17,11 @@ public static void register(CommandDispatcher dispatcher) {
private static LiteralArgumentBuilder root() {
return Commands.literal("bannermod")
+ .then(AdminDebugCommands.debug())
+ .then(AdminRecoveryCommands.settlement())
+ .then(AdminRecoveryCommands.treasury())
+ .then(AdminRecoveryCommands.claim())
+ .then(AdminRecoveryCommands.worker())
.then(PoliticalRegistryCommands.build())
.then(WarDeclarationCommands.build()
.then(SiegeStandardCommands.build())
diff --git a/src/main/java/com/talhanation/bannermod/commands/war/PoliticalRegistryCommands.java b/src/main/java/com/talhanation/bannermod/commands/war/PoliticalRegistryCommands.java
index 668227e0..dc3fba98 100644
--- a/src/main/java/com/talhanation/bannermod/commands/war/PoliticalRegistryCommands.java
+++ b/src/main/java/com/talhanation/bannermod/commands/war/PoliticalRegistryCommands.java
@@ -10,8 +10,8 @@
import com.talhanation.bannermod.war.cooldown.WarCooldownRuntime;
import com.talhanation.bannermod.persistence.military.RecruitsClaim;
import com.talhanation.bannermod.persistence.military.RecruitsClaimSaveData;
-import com.talhanation.bannermod.settlement.BannerModSettlementManager;
-import com.talhanation.bannermod.settlement.BannerModSettlementSnapshot;
+import com.talhanation.bannermod.settlement.SettlementManager;
+import com.talhanation.bannermod.settlement.SettlementSnapshot;
import com.talhanation.bannermod.war.registry.PoliticalEntityRecord;
import com.talhanation.bannermod.war.registry.PoliticalEntityStatus;
import com.talhanation.bannermod.war.registry.PoliticalRegistryRuntime;
@@ -169,14 +169,14 @@ private static int setStatus(com.mojang.brigadier.context.CommandContext settlementSnapshotForEntity(
+ private static Optional settlementSnapshotForEntity(
com.mojang.brigadier.context.CommandContext context,
UUID politicalEntityId) {
var level = WarCommandSupport.level(context);
- BannerModSettlementManager settlements = BannerModSettlementManager.get(level);
+ SettlementManager settlements = SettlementManager.get(level);
for (RecruitsClaim claim : RecruitsClaimSaveData.get(level).getAllClaims()) {
if (politicalEntityId.equals(claim.getOwnerPoliticalEntityId())) {
- BannerModSettlementSnapshot snapshot = settlements.getSnapshot(claim.getUUID());
+ SettlementSnapshot snapshot = settlements.getSnapshot(claim.getUUID());
if (snapshot != null) {
return Optional.of(snapshot);
}
diff --git a/src/main/java/com/talhanation/bannermod/commands/war/WarDeclarationCommands.java b/src/main/java/com/talhanation/bannermod/commands/war/WarDeclarationCommands.java
index 57031ca6..3ec4089f 100644
--- a/src/main/java/com/talhanation/bannermod/commands/war/WarDeclarationCommands.java
+++ b/src/main/java/com/talhanation/bannermod/commands/war/WarDeclarationCommands.java
@@ -5,6 +5,7 @@
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import com.talhanation.bannermod.events.ClaimEvents;
@@ -38,6 +39,13 @@
import java.util.concurrent.CompletableFuture;
public final class WarDeclarationCommands {
+ private static final SimpleCommandExceptionType ERR_INVALID_WAR_ID = new SimpleCommandExceptionType(
+ Component.literal("warId must be a valid UUID")
+ );
+ private static final SimpleCommandExceptionType ERR_SERVER_ONLY = new SimpleCommandExceptionType(
+ Component.literal("This command can only run on a server")
+ );
+
private WarDeclarationCommands() {
}
@@ -62,6 +70,10 @@ public static LiteralArgumentBuilder build() {
.then(Commands.literal("cancel")
.then(Commands.argument("warId", StringArgumentType.word())
.executes(ctx -> resolve(ctx, ResolveMode.CANCEL, 0L))))
+ .then(Commands.literal("wipe")
+ .requires(source -> source.hasPermission(2))
+ .then(Commands.argument("warId", StringArgumentType.word())
+ .executes(WarDeclarationCommands::wipe)))
.then(Commands.literal("whitepeace")
.requires(source -> source.hasPermission(2))
.then(Commands.argument("warId", StringArgumentType.word())
@@ -209,6 +221,39 @@ private static int resolve(com.mojang.brigadier.context.CommandContext context)
+ throws CommandSyntaxException {
+ UUID warId = parseWarId(StringArgumentType.getString(context, "warId"));
+ ServerLevel level = context.getSource().getLevel();
+ if (level == null || level.isClientSide()) {
+ throw ERR_SERVER_ONLY.create();
+ }
+ WarDeclarationRuntime declarations = WarRuntimeContext.declarations(level);
+ if (declarations.byId(warId).isEmpty()) {
+ throw WarCommandSupport.ERR_WAR_NOT_FOUND.create();
+ }
+
+ int removedSieges = 0;
+ for (var siege : WarRuntimeContext.sieges(level).forWar(warId)) {
+ if (WarRuntimeContext.sieges(level).remove(siege.id())) {
+ removedSieges++;
+ }
+ }
+ int removedInvites = WarRuntimeContext.allyInvites(level).removeForWar(warId);
+ declarations.remove(warId);
+ WarCommandSupport.reply(context, "Wiped war " + warId
+ + " (siege standards=" + removedSieges + ", ally invites=" + removedInvites + ")");
+ return 1;
+ }
+
+ private static UUID parseWarId(String token) throws CommandSyntaxException {
+ try {
+ return UUID.fromString(token);
+ } catch (IllegalArgumentException exception) {
+ throw ERR_INVALID_WAR_ID.create();
+ }
+ }
+
private static int vassalize(com.mojang.brigadier.context.CommandContext context)
throws CommandSyntaxException {
String token = StringArgumentType.getString(context, "warId");
diff --git a/src/main/java/com/talhanation/bannermod/entity/civilian/AnimalFarmerEntity.java b/src/main/java/com/talhanation/bannermod/entity/civilian/AnimalFarmerEntity.java
index 0c51acf4..8eb43a16 100644
--- a/src/main/java/com/talhanation/bannermod/entity/civilian/AnimalFarmerEntity.java
+++ b/src/main/java/com/talhanation/bannermod/entity/civilian/AnimalFarmerEntity.java
@@ -3,7 +3,6 @@
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.ai.pathfinding.AsyncGroundPathNavigation;
import com.talhanation.bannermod.config.WorkersServerConfig;
-import com.talhanation.bannermod.ai.civilian.AnimalFarmerWorkGoal;
import com.talhanation.bannermod.entity.civilian.workarea.AnimalPenArea;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
@@ -33,12 +32,6 @@ public AnimalFarmerEntity(EntityType extends AbstractWorkerEntity> entityType,
super(entityType, world);
}
- @Override
- protected void registerGoals() {
- super.registerGoals();
- this.goalSelector.addGoal(0, new AnimalFarmerWorkGoal(this));
- }
-
public static AttributeSupplier.Builder setAttributes() {
return Mob.createMobAttributes()
.add(Attributes.MAX_HEALTH, 40.0D)
diff --git a/src/main/java/com/talhanation/bannermod/entity/civilian/BuilderEntity.java b/src/main/java/com/talhanation/bannermod/entity/civilian/BuilderEntity.java
index 4ef04f88..4aa5f60c 100644
--- a/src/main/java/com/talhanation/bannermod/entity/civilian/BuilderEntity.java
+++ b/src/main/java/com/talhanation/bannermod/entity/civilian/BuilderEntity.java
@@ -3,7 +3,6 @@
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.ai.pathfinding.AsyncGroundPathNavigation;
import com.talhanation.bannermod.config.WorkersServerConfig;
-import com.talhanation.bannermod.ai.civilian.BuilderWorkGoal;
import com.talhanation.bannermod.entity.civilian.workarea.BuildArea;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
@@ -34,12 +33,6 @@ public BuilderEntity(EntityType extends AbstractWorkerEntity> entityType, Leve
super(entityType, world);
}
- @Override
- protected void registerGoals() {
- super.registerGoals();
- this.goalSelector.addGoal(0, new BuilderWorkGoal(this));
- }
-
public static AttributeSupplier.Builder setAttributes() {
return Mob.createMobAttributes()
.add(Attributes.MAX_HEALTH, 40.0D)
diff --git a/src/main/java/com/talhanation/bannermod/entity/civilian/FarmerEntity.java b/src/main/java/com/talhanation/bannermod/entity/civilian/FarmerEntity.java
index 6cdefdc7..abac1b4b 100644
--- a/src/main/java/com/talhanation/bannermod/entity/civilian/FarmerEntity.java
+++ b/src/main/java/com/talhanation/bannermod/entity/civilian/FarmerEntity.java
@@ -4,7 +4,6 @@
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.ai.pathfinding.AsyncGroundPathNavigation;
import com.talhanation.bannermod.config.WorkersServerConfig;
-import com.talhanation.bannermod.ai.civilian.FarmerWorkGoal;
import com.talhanation.bannermod.entity.civilian.workarea.CropArea;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
@@ -44,12 +43,6 @@ public FarmerEntity(EntityType extends AbstractWorkerEntity> entityType, Level
}
- @Override
- protected void registerGoals() {
- super.registerGoals();
- this.goalSelector.addGoal(0, new FarmerWorkGoal(this));
- }
-
public static AttributeSupplier.Builder setAttributes() {
return Mob.createMobAttributes()
.add(Attributes.MAX_HEALTH, 20.0D)
diff --git a/src/main/java/com/talhanation/bannermod/entity/civilian/FishermanEntity.java b/src/main/java/com/talhanation/bannermod/entity/civilian/FishermanEntity.java
index c9c72371..a4ba28c9 100644
--- a/src/main/java/com/talhanation/bannermod/entity/civilian/FishermanEntity.java
+++ b/src/main/java/com/talhanation/bannermod/entity/civilian/FishermanEntity.java
@@ -3,13 +3,15 @@
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.ai.pathfinding.AsyncGroundPathNavigation;
import com.talhanation.bannermod.config.WorkersServerConfig;
-import com.talhanation.bannermod.ai.civilian.FishermanWorkGoal;
import com.talhanation.bannermod.entity.civilian.workarea.FishingArea;
+import net.minecraft.server.MinecraftServer;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
+import net.minecraft.world.InteractionHand;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
@@ -19,8 +21,14 @@
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.*;
+import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerLevelAccessor;
+import net.minecraft.world.level.storage.loot.BuiltInLootTables;
+import net.minecraft.world.level.storage.loot.LootParams;
+import net.minecraft.world.level.storage.loot.LootTable;
+import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
+import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.common.NeoForgeMod;
import net.minecraft.core.registries.BuiltInRegistries;
@@ -34,12 +42,6 @@ public FishermanEntity(EntityType extends AbstractWorkerEntity> entityType, Le
super(entityType, world);
}
- @Override
- protected void registerGoals() {
- super.registerGoals();
- this.goalSelector.addGoal(0, new FishermanWorkGoal(this));
- }
-
public static AttributeSupplier.Builder setAttributes() {
return Mob.createMobAttributes()
.add(Attributes.MAX_HEALTH, 20.0D)
@@ -136,4 +138,29 @@ public FishingBobberEntity throwFishingHook(Vec3 target){
return fishingBobber;
}
+
+ public void spawnFishingLoot(FishingBobberEntity fishingBobber) {
+ if(fishingBobber == null ) return;
+
+ ServerLevel serverLevel = (ServerLevel)this.getCommandSenderWorld();
+ double luckFromTool = EnchantmentHelper.getFishingLuckBonus(serverLevel, this.getItemInHand(InteractionHand.MAIN_HAND), this);
+ double luckFromDepth = Math.min(25, fishingBobber.getWaterDepth())/10F;
+ double luck = 0.1D + luckFromTool + luckFromDepth;
+
+ LootParams lootparams = (new LootParams.Builder(serverLevel))
+ .withParameter(LootContextParams.ORIGIN, this.position())
+ .withParameter(LootContextParams.TOOL, getMainHandItem())
+ .withParameter(LootContextParams.ATTACKING_ENTITY, this)
+ .withLuck((float)(luck + luckFromTool))
+ .create(LootContextParamSets.FISHING);
+ LootTable loottable = this.getCommandSenderWorld().getServer().reloadableRegistries().getLootTable(BuiltInLootTables.FISHING);
+ List list = loottable.getRandomItems(lootparams);
+
+ MinecraftServer server = getServer();
+ if (server == null) return;
+
+ for (ItemStack itemstack : list) {
+ getInventory().addItem(itemstack);
+ }
+ }
}
diff --git a/src/main/java/com/talhanation/bannermod/entity/civilian/LumberjackEntity.java b/src/main/java/com/talhanation/bannermod/entity/civilian/LumberjackEntity.java
index 97032295..b665c145 100644
--- a/src/main/java/com/talhanation/bannermod/entity/civilian/LumberjackEntity.java
+++ b/src/main/java/com/talhanation/bannermod/entity/civilian/LumberjackEntity.java
@@ -3,7 +3,6 @@
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.ai.pathfinding.AsyncGroundPathNavigation;
import com.talhanation.bannermod.config.WorkersServerConfig;
-import com.talhanation.bannermod.ai.civilian.LumberjackWorkGoal;
import com.talhanation.bannermod.entity.civilian.workarea.LumberArea;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
@@ -34,12 +33,6 @@ public LumberjackEntity(EntityType extends AbstractWorkerEntity> entityType, L
super(entityType, world);
}
- @Override
- protected void registerGoals() {
- super.registerGoals();
- this.goalSelector.addGoal(0, new LumberjackWorkGoal(this));
- }
-
public static AttributeSupplier.Builder setAttributes() {
return Mob.createMobAttributes()
.add(Attributes.MAX_HEALTH, 20.0D)
diff --git a/src/main/java/com/talhanation/bannermod/entity/civilian/MerchantEntity.java b/src/main/java/com/talhanation/bannermod/entity/civilian/MerchantEntity.java
index d35a16b9..33ccbbc3 100644
--- a/src/main/java/com/talhanation/bannermod/entity/civilian/MerchantEntity.java
+++ b/src/main/java/com/talhanation/bannermod/entity/civilian/MerchantEntity.java
@@ -5,7 +5,6 @@
import com.talhanation.bannermod.ai.pathfinding.AsyncGroundPathNavigation;
import com.talhanation.bannermod.bootstrap.BannerModMain;
import com.talhanation.bannermod.config.WorkersServerConfig;
-import com.talhanation.bannermod.ai.civilian.MerchantWorkGoal;
import com.talhanation.bannermod.entity.civilian.workarea.MarketArea;
import com.talhanation.bannermod.events.ClaimEvents;
import com.talhanation.bannermod.governance.BannerModGovernorManager;
@@ -14,8 +13,8 @@
import com.talhanation.bannermod.network.messages.civilian.MessageOpenMerchantEditTradeScreen;
import com.talhanation.bannermod.network.messages.civilian.MessageOpenMerchantTradeScreen;
import com.talhanation.bannermod.persistence.civilian.WorkersMerchantTrade;
-import com.talhanation.bannermod.settlement.BannerModSettlementManager;
-import com.talhanation.bannermod.settlement.BannerModSettlementService;
+import com.talhanation.bannermod.settlement.SettlementManager;
+import com.talhanation.bannermod.settlement.SettlementService;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.syncher.EntityDataAccessor;
@@ -113,12 +112,6 @@ public List- inventoryInputHelp() {
return null;
}
- @Override
- protected void registerGoals() {
- super.registerGoals();
- this.goalSelector.addGoal(3, new MerchantWorkGoal(this));
- }
-
@Nullable
public MarketArea getCurrentMarketArea() {
return getCurrentWorkArea() instanceof MarketArea ma ? ma : null;
@@ -550,10 +543,10 @@ private void refreshSettlementSnapshot() {
if (!(this.level() instanceof ServerLevel serverLevel) || market == null || ClaimEvents.claimManager() == null) {
return;
}
- BannerModSettlementService.refreshClaimAt(
+ SettlementService.refreshClaimAt(
serverLevel,
ClaimEvents.claimManager(),
- BannerModSettlementManager.get(serverLevel),
+ SettlementManager.get(serverLevel),
BannerModGovernorManager.get(serverLevel),
market.blockPosition()
);
diff --git a/src/main/java/com/talhanation/bannermod/entity/civilian/MinerEntity.java b/src/main/java/com/talhanation/bannermod/entity/civilian/MinerEntity.java
index 99d6e10c..3c4c4f59 100644
--- a/src/main/java/com/talhanation/bannermod/entity/civilian/MinerEntity.java
+++ b/src/main/java/com/talhanation/bannermod/entity/civilian/MinerEntity.java
@@ -3,7 +3,6 @@
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.ai.pathfinding.AsyncGroundPathNavigation;
import com.talhanation.bannermod.config.WorkersServerConfig;
-import com.talhanation.bannermod.ai.civilian.MinerWorkGoal;
import com.talhanation.bannermod.entity.civilian.workarea.MiningArea;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
@@ -36,12 +35,6 @@ public MinerEntity(EntityType extends AbstractWorkerEntity> entityType, Level
super(entityType, world);
}
- @Override
- protected void registerGoals() {
- super.registerGoals();
- this.goalSelector.addGoal(0, new MinerWorkGoal(this));
- }
-
public static AttributeSupplier.Builder setAttributes() {
return Mob.createMobAttributes()
.add(Attributes.MAX_HEALTH, 40.0D)
diff --git a/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerControlAccess.java b/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerControlAccess.java
index cf34b9e4..8b04bd9f 100644
--- a/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerControlAccess.java
+++ b/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerControlAccess.java
@@ -2,8 +2,8 @@
import com.talhanation.bannermod.events.ClaimEvents;
import com.talhanation.bannermod.governance.BannerModGovernorManager;
-import com.talhanation.bannermod.settlement.BannerModSettlementManager;
-import com.talhanation.bannermod.settlement.BannerModSettlementService;
+import com.talhanation.bannermod.settlement.SettlementManager;
+import com.talhanation.bannermod.settlement.SettlementService;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Player;
@@ -65,10 +65,10 @@ private void refreshSettlementSnapshot() {
if (!(this.worker.level() instanceof ServerLevel serverLevel) || ClaimEvents.claimManager() == null) {
return;
}
- BannerModSettlementService.refreshClaimAt(
+ SettlementService.refreshClaimAt(
serverLevel,
ClaimEvents.claimManager(),
- BannerModSettlementManager.get(serverLevel),
+ SettlementManager.get(serverLevel),
BannerModGovernorManager.get(serverLevel),
this.worker.blockPosition()
);
diff --git a/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerDismissService.java b/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerDismissService.java
new file mode 100644
index 00000000..c55973b9
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerDismissService.java
@@ -0,0 +1,41 @@
+package com.talhanation.bannermod.entity.civilian;
+
+import com.talhanation.bannermod.shared.settlement.BannerModSettlementRefreshSupport;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+
+import javax.annotation.Nullable;
+
+public final class WorkerDismissService {
+ private WorkerDismissService() {
+ }
+
+ @Nullable
+ public static String dismissDeniedReasonKey(@Nullable ServerPlayer player, @Nullable AbstractWorkerEntity worker) {
+ if (player == null || worker == null || !(worker.level() instanceof ServerLevel)) {
+ return "chat.bannermod.workerui.dismiss.denied.missing";
+ }
+ if (!worker.isAlive() || worker.isRemoved()) {
+ return "chat.bannermod.workerui.dismiss.denied.dead";
+ }
+ if (player.distanceToSqr(worker) > 16.0D * 16.0D) {
+ return "chat.bannermod.workerui.dismiss.denied.too_far";
+ }
+ if (player.getUUID().equals(worker.getOwnerUUID()) || player.hasPermissions(2)) {
+ return null;
+ }
+ return "chat.bannermod.workerui.dismiss.denied.not_owner";
+ }
+
+ public static boolean dismiss(@Nullable ServerPlayer player, @Nullable AbstractWorkerEntity worker) {
+ if (dismissDeniedReasonKey(player, worker) != null || worker == null || !(worker.level() instanceof ServerLevel serverLevel)) {
+ return false;
+ }
+ if (worker.getCurrentWorkArea() != null) {
+ worker.getCurrentWorkArea().setBeingWorkedOn(false);
+ }
+ worker.discard();
+ BannerModSettlementRefreshSupport.refreshSnapshot(serverLevel, worker.blockPosition());
+ return true;
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerIndex.java b/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerIndex.java
index f5e0d058..723bcd87 100644
--- a/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerIndex.java
+++ b/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerIndex.java
@@ -114,6 +114,23 @@ public Optional
> queryInClaim(ServerLevel level, Recr
return Optional.of(List.copyOf(workers));
}
+ public int countInChunk(ServerLevel level, ChunkPos chunkPos, boolean aliveOnly) {
+ if (level == null || chunkPos == null) return 0;
+ Map> chunks = byLevel.get(level.dimension());
+ if (chunks == null) return 0;
+ Set uuids = chunks.get(chunkPos);
+ if (uuids == null || uuids.isEmpty()) return 0;
+ if (!aliveOnly) return uuids.size();
+ int count = 0;
+ for (UUID uuid : uuids) {
+ Entity entity = level.getEntity(uuid);
+ if (entity instanceof AbstractWorkerEntity worker && worker.isAlive()) {
+ count++;
+ }
+ }
+ return count;
+ }
+
public void clear(ResourceKey dimension) {
if (dimension == null) return;
byLevel.remove(dimension);
diff --git a/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerRuntimeLoop.java b/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerRuntimeLoop.java
index 172f4c72..1e5200b5 100644
--- a/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerRuntimeLoop.java
+++ b/src/main/java/com/talhanation/bannermod/entity/civilian/WorkerRuntimeLoop.java
@@ -2,6 +2,7 @@
import com.talhanation.bannermod.util.RuntimeProfilingCounters;
import com.talhanation.bannermod.entity.civilian.workarea.AbstractWorkAreaEntity;
+import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.item.ItemEntity;
import java.util.List;
@@ -15,6 +16,7 @@ private WorkerRuntimeLoop() {
static void aiStep(AbstractWorkerEntity worker) {
tickLootPickup(worker);
releaseDistantWorkArea(worker);
+ reportMissingWorkArea(worker);
}
private static void tickLootPickup(AbstractWorkerEntity worker) {
@@ -57,4 +59,20 @@ private static void releaseDistantWorkArea(AbstractWorkerEntity worker) {
workArea.setBeingWorkedOn(false);
}
}
+
+ private static void reportMissingWorkArea(AbstractWorkerEntity worker) {
+ if (!worker.shouldWork() || worker.getCurrentWorkArea() != null) {
+ return;
+ }
+
+ if (worker instanceof FarmerEntity) {
+ worker.reportIdleReason("farmer_no_area", Component.literal(worker.getName().getString() + ": Waiting for a crop area."));
+ } else if (worker instanceof MinerEntity) {
+ worker.reportIdleReason("miner_no_area", Component.literal(worker.getName().getString() + ": Waiting for a mining area."));
+ } else if (worker instanceof LumberjackEntity) {
+ worker.reportIdleReason("lumberjack_no_area", Component.literal(worker.getName().getString() + ": Waiting for a lumber area."));
+ } else if (worker instanceof BuilderEntity) {
+ worker.reportIdleReason("builder_no_area", Component.literal(worker.getName().getString() + ": Waiting for a build area."));
+ }
+ }
}
diff --git a/src/main/java/com/talhanation/bannermod/entity/civilian/workarea/BuildArea.java b/src/main/java/com/talhanation/bannermod/entity/civilian/workarea/BuildArea.java
index 6c559e91..fb18d260 100644
--- a/src/main/java/com/talhanation/bannermod/entity/civilian/workarea/BuildArea.java
+++ b/src/main/java/com/talhanation/bannermod/entity/civilian/workarea/BuildArea.java
@@ -8,7 +8,7 @@
import com.talhanation.bannermod.persistence.civilian.BuildBlockParse;
import com.talhanation.bannermod.persistence.civilian.StructureManager;
import com.talhanation.bannermod.settlement.prefab.staffing.PrefabAutoStaffingRuntime;
-import com.talhanation.bannermod.settlement.project.BannerModSettlementProjectRuntime;
+import com.talhanation.bannermod.settlement.project.SettlementProjectRuntime;
import com.talhanation.bannermod.shared.settlement.BannerModSettlementRefreshSupport;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@@ -150,7 +150,7 @@ public void setStartBuild(boolean isCreative) {
this.resumePlanPending = false;
this.setDone(false);
if (this.getCommandSenderWorld() instanceof ServerLevel serverLevel) {
- BannerModSettlementProjectRuntime.onBuildAreaStarted(serverLevel, this.getUUID());
+ SettlementProjectRuntime.onBuildAreaStarted(serverLevel, this.getUUID());
}
stackToPlace.clear();
stackToBreak.clear();
@@ -213,7 +213,7 @@ public void setDone(boolean done) {
boolean wasDone = this.isDone();
super.setDone(done);
if (done && !wasDone && this.getCommandSenderWorld() instanceof ServerLevel serverLevel) {
- BannerModSettlementProjectRuntime.onBuildAreaCompleted(serverLevel, this.getUUID());
+ SettlementProjectRuntime.onBuildAreaCompleted(serverLevel, this.getUUID());
}
}
diff --git a/src/main/java/com/talhanation/bannermod/entity/civilian/workarea/WorkAreaIndex.java b/src/main/java/com/talhanation/bannermod/entity/civilian/workarea/WorkAreaIndex.java
index b48bfcad..56cc855b 100644
--- a/src/main/java/com/talhanation/bannermod/entity/civilian/workarea/WorkAreaIndex.java
+++ b/src/main/java/com/talhanation/bannermod/entity/civilian/workarea/WorkAreaIndex.java
@@ -167,6 +167,22 @@ public List queryInChunks(ServerLevel leve
return results;
}
+ public int countInChunk(ServerLevel level, ChunkPos chunkPos, Class extends AbstractWorkAreaEntity> type) {
+ if (level == null || chunkPos == null || type == null) return 0;
+ Map> chunks = byLevel.get(level.dimension());
+ if (chunks == null) return 0;
+ Set uuids = chunks.get(chunkPos);
+ if (uuids == null || uuids.isEmpty()) return 0;
+ int count = 0;
+ for (UUID uuid : uuids) {
+ Entity entity = level.getEntity(uuid);
+ if (type.isInstance(entity) && entity.isAlive()) {
+ count++;
+ }
+ }
+ return count;
+ }
+
/** Total entries tracked in a given level (diagnostics only). */
public int sizeFor(ResourceKey dimension) {
Map> chunks = byLevel.get(dimension);
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/AbstractRecruitEntity.java b/src/main/java/com/talhanation/bannermod/entity/military/AbstractRecruitEntity.java
index 2d97d96a..c1358f04 100644
--- a/src/main/java/com/talhanation/bannermod/entity/military/AbstractRecruitEntity.java
+++ b/src/main/java/com/talhanation/bannermod/entity/military/AbstractRecruitEntity.java
@@ -6,8 +6,9 @@
import com.talhanation.bannermod.citizen.CitizenPersistenceBridge;
import com.talhanation.bannermod.citizen.CitizenRole;
import com.talhanation.bannermod.entity.citizen.AbstractCitizenEntity;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.events.*;
-import com.talhanation.bannermod.events.RecruitEvent;
+import com.talhanation.bannermod.api.event.RecruitEvent;
import com.talhanation.bannermod.compat.IWeapon;
import com.talhanation.bannermod.config.RecruitsClientConfig;
import com.talhanation.bannermod.config.RecruitsServerConfig;
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/AssassinLeaderCountAuthority.java b/src/main/java/com/talhanation/bannermod/entity/military/AssassinLeaderCountAuthority.java
new file mode 100644
index 00000000..8f959d0c
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/entity/military/AssassinLeaderCountAuthority.java
@@ -0,0 +1,18 @@
+package com.talhanation.bannermod.entity.military;
+
+import java.util.UUID;
+import java.util.function.IntConsumer;
+
+public final class AssassinLeaderCountAuthority {
+ private AssassinLeaderCountAuthority() {
+ }
+
+ public static boolean trySetCount(UUID controlOwnerUUID, UUID senderUUID, boolean senderHasOpPermission,
+ int count, IntConsumer countSetter) {
+ if ((controlOwnerUUID != null && controlOwnerUUID.equals(senderUUID)) || senderHasOpPermission) {
+ countSetter.accept(count);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/AssassinLeaderEntity.java b/src/main/java/com/talhanation/bannermod/entity/military/AssassinLeaderEntity.java
index bf14e3a2..871e1d86 100644
--- a/src/main/java/com/talhanation/bannermod/entity/military/AssassinLeaderEntity.java
+++ b/src/main/java/com/talhanation/bannermod/entity/military/AssassinLeaderEntity.java
@@ -193,6 +193,11 @@ public boolean isControlledBy(Player player) {
return this.controlOwnerUUID != null && this.controlOwnerUUID.equals(player.getUUID());
}
+ public boolean trySetCountFrom(UUID senderUUID, boolean senderHasOpPermission, int count) {
+ return AssassinLeaderCountAuthority.trySetCount(this.controlOwnerUUID, senderUUID, senderHasOpPermission,
+ count, this::setCount);
+ }
+
@Nullable
public UUID getControlOwnerUUID() {
return controlOwnerUUID;
@@ -216,5 +221,3 @@ public int getMaxAssassinCount(){
-
-
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/RecruitCombatDecisions.java b/src/main/java/com/talhanation/bannermod/entity/military/RecruitCombatDecisions.java
index 9062c1ce..5ff31344 100644
--- a/src/main/java/com/talhanation/bannermod/entity/military/RecruitCombatDecisions.java
+++ b/src/main/java/com/talhanation/bannermod/entity/military/RecruitCombatDecisions.java
@@ -2,7 +2,7 @@
import com.talhanation.bannermod.ai.military.UnitTypeMatchup;
import com.talhanation.bannermod.ai.military.WeaponReach;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/RecruitCombatOverrideService.java b/src/main/java/com/talhanation/bannermod/entity/military/RecruitCombatOverrideService.java
index c80664ef..71692f42 100644
--- a/src/main/java/com/talhanation/bannermod/entity/military/RecruitCombatOverrideService.java
+++ b/src/main/java/com/talhanation/bannermod/entity/military/RecruitCombatOverrideService.java
@@ -10,7 +10,7 @@
import com.talhanation.bannermod.ai.military.ShieldBlockGeometry;
import com.talhanation.bannermod.ai.military.ShieldMitigation;
import com.talhanation.bannermod.combat.FormationPlanner;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.DamageTypeTags;
import net.minecraft.util.Mth;
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/RecruitIndex.java b/src/main/java/com/talhanation/bannermod/entity/military/RecruitIndex.java
index 0c91d34c..f70b7085 100644
--- a/src/main/java/com/talhanation/bannermod/entity/military/RecruitIndex.java
+++ b/src/main/java/com/talhanation/bannermod/entity/military/RecruitIndex.java
@@ -318,6 +318,23 @@ public long version(ServerLevel level) {
return version == null ? 0L : version.get();
}
+ public int countInChunk(ServerLevel level, ChunkPos chunkPos, boolean aliveOnly) {
+ if (level == null || chunkPos == null) return 0;
+ LevelIndex index = byLevel.get(level.dimension());
+ if (index == null) return 0;
+ Set uuids = index.byChunk.get(chunkPos);
+ if (uuids == null || uuids.isEmpty()) return 0;
+ if (!aliveOnly) return uuids.size();
+ int count = 0;
+ for (UUID uuid : uuids) {
+ Entity entity = level.getEntity(uuid);
+ if (entity instanceof AbstractRecruitEntity recruit && recruit.isAlive()) {
+ count++;
+ }
+ }
+ return count;
+ }
+
public void resetCounters() {
counters.reset();
}
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/RecruitInteractionService.java b/src/main/java/com/talhanation/bannermod/entity/military/RecruitInteractionService.java
index 275edbda..0a1da02a 100644
--- a/src/main/java/com/talhanation/bannermod/entity/military/RecruitInteractionService.java
+++ b/src/main/java/com/talhanation/bannermod/entity/military/RecruitInteractionService.java
@@ -2,7 +2,7 @@
import com.talhanation.bannermod.bootstrap.BannerModMain;
import com.talhanation.bannermod.events.CommandEvents;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.inventory.military.DebugInvMenu;
import com.talhanation.bannermod.inventory.military.RecruitHireMenu;
import com.talhanation.bannermod.inventory.military.RecruitInventoryMenu;
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/RecruitLifecycleService.java b/src/main/java/com/talhanation/bannermod/entity/military/RecruitLifecycleService.java
index 84cd1fb1..bef9c6c3 100644
--- a/src/main/java/com/talhanation/bannermod/entity/military/RecruitLifecycleService.java
+++ b/src/main/java/com/talhanation/bannermod/entity/military/RecruitLifecycleService.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod.entity.military;
-import com.talhanation.bannermod.events.RecruitEvent;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.api.event.RecruitEvent;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.persistence.military.RecruitsGroup;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/RecruitPersistenceBridge.java b/src/main/java/com/talhanation/bannermod/entity/military/RecruitPersistenceBridge.java
index 218f4c6e..0851861a 100644
--- a/src/main/java/com/talhanation/bannermod/entity/military/RecruitPersistenceBridge.java
+++ b/src/main/java/com/talhanation/bannermod/entity/military/RecruitPersistenceBridge.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod.entity.military;
import com.talhanation.bannermod.citizen.CitizenRole;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/RecruitProgressionService.java b/src/main/java/com/talhanation/bannermod/entity/military/RecruitProgressionService.java
index a0997d0c..2d8a751c 100644
--- a/src/main/java/com/talhanation/bannermod/entity/military/RecruitProgressionService.java
+++ b/src/main/java/com/talhanation/bannermod/entity/military/RecruitProgressionService.java
@@ -2,7 +2,7 @@
import com.talhanation.bannermod.bootstrap.BannerModMain;
import com.talhanation.bannermod.config.RecruitsServerConfig;
-import com.talhanation.bannermod.events.RecruitEvent;
+import com.talhanation.bannermod.api.event.RecruitEvent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.ai.attributes.Attributes;
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/VillagerNobleEntity.java b/src/main/java/com/talhanation/bannermod/entity/military/VillagerNobleEntity.java
index 4320929e..1519e3ea 100644
--- a/src/main/java/com/talhanation/bannermod/entity/military/VillagerNobleEntity.java
+++ b/src/main/java/com/talhanation/bannermod/entity/military/VillagerNobleEntity.java
@@ -2,7 +2,7 @@
import com.talhanation.bannermod.bootstrap.BannerModMain;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.config.RecruitsServerConfig;
import com.talhanation.bannermod.ai.military.UseShield;
import com.talhanation.bannermod.network.messages.military.MessageToClientOpenNobleTradeScreen;
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/perks/PerkProgress.java b/src/main/java/com/talhanation/bannermod/entity/military/perks/PerkProgress.java
index bd0a359e..e3efc043 100644
--- a/src/main/java/com/talhanation/bannermod/entity/military/perks/PerkProgress.java
+++ b/src/main/java/com/talhanation/bannermod/entity/military/perks/PerkProgress.java
@@ -4,6 +4,8 @@
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
+import net.minecraft.core.HolderLookup;
+import net.neoforged.neoforge.common.util.INBTSerializable;
import java.util.Collections;
import java.util.LinkedHashSet;
@@ -26,7 +28,7 @@
* touched.
*
*/
-public final class PerkProgress {
+public final class PerkProgress implements INBTSerializable {
private static final String NBT_POINTS = "AvailablePoints";
private static final String NBT_OWNED = "OwnedPerks";
@@ -103,6 +105,11 @@ public CompoundTag toNbt() {
return tag;
}
+ @Override
+ public CompoundTag serializeNBT(HolderLookup.Provider provider) {
+ return toNbt();
+ }
+
public void fromNbt(CompoundTag tag) {
owned.clear();
availablePoints = 0;
@@ -120,4 +127,9 @@ public void fromNbt(CompoundTag tag) {
}
}
}
+
+ @Override
+ public void deserializeNBT(HolderLookup.Provider provider, CompoundTag nbt) {
+ fromNbt(nbt);
+ }
}
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/perks/PerkRegistry.java b/src/main/java/com/talhanation/bannermod/entity/military/perks/PerkRegistry.java
index c4fcd03c..2bcae89c 100644
--- a/src/main/java/com/talhanation/bannermod/entity/military/perks/PerkRegistry.java
+++ b/src/main/java/com/talhanation/bannermod/entity/military/perks/PerkRegistry.java
@@ -9,10 +9,7 @@
import java.util.Optional;
/**
- * In-memory perk catalog. Phase 1 (SKILLTREE-002) seeds a tiny placeholder set
- * so persistence + skill-point grant can be exercised end-to-end; SKILLTREE-003
- * authors the per-archetype catalogs and SKILLTREE-004 adds the player-facing
- * general-stat tree on top of the same lookup API.
+ * Server-owned in-memory perk catalog populated from datapack JSON during reload.
*
* Server-authoritative: every {@link PerkNode} lives in the JVM, never on
* the wire. Identifiers are deliberately stable strings so save data written
@@ -23,28 +20,30 @@ public final class PerkRegistry {
private static final Map> BY_ARCHETYPE = new EnumMap<>(PerkArchetype.class);
static {
- for (PerkArchetype archetype : PerkArchetype.values()) {
- BY_ARCHETYPE.put(archetype, new ArrayList<>());
- }
- seedPlaceholderCatalog();
+ replaceAll(defaultNodes());
}
private PerkRegistry() {
}
- /**
- * Registers a perk; later phases call this from their catalog initializers.
- * Idempotent on identical re-registration to keep gametest reload safe;
- * conflicting redefinitions throw so author errors surface immediately.
- */
- public static synchronized void register(PerkNode node) {
- PerkNode existing = BY_ID.get(node.id());
- if (existing != null) {
- if (existing.equals(node)) return;
- throw new IllegalStateException("Perk id already registered with different payload: " + node.id());
+ public static synchronized void replaceAll(List nodes) {
+ Map byId = new HashMap<>();
+ Map> byArchetype = new EnumMap<>(PerkArchetype.class);
+ for (PerkArchetype archetype : PerkArchetype.values()) {
+ byArchetype.put(archetype, new ArrayList<>());
}
- BY_ID.put(node.id(), node);
- BY_ARCHETYPE.get(node.archetype()).add(node);
+ for (PerkNode node : nodes) {
+ PerkNode existing = byId.putIfAbsent(node.id(), node);
+ if (existing != null) {
+ throw new IllegalStateException("Duplicate perk id: " + node.id());
+ }
+ byArchetype.get(node.archetype()).add(node);
+ }
+
+ BY_ID.clear();
+ BY_ID.putAll(byId);
+ BY_ARCHETYPE.clear();
+ BY_ARCHETYPE.putAll(byArchetype);
}
public static Optional get(String id) {
@@ -63,28 +62,21 @@ public static boolean isKnown(String id) {
return BY_ID.containsKey(id);
}
- /**
- * Seeds one placeholder perk per archetype + one universal perk so the
- * registry is non-empty and downstream tests have observable ids to query.
- * Catalog authoring proper happens in SKILLTREE-003/004.
- */
- private static void seedPlaceholderCatalog() {
- registerInternal(PerkNode.leaf("universal/toughness_i", PerkArchetype.UNIVERSAL, 1,
- new PerkBonus(PerkStat.MAX_HEALTH, 2.0D)));
- registerInternal(PerkNode.leaf("swordsman/iron_grip_i", PerkArchetype.SWORDSMAN, 1,
- new PerkBonus(PerkStat.ATTACK_DAMAGE, 0.5D)));
- registerInternal(PerkNode.leaf("bowman/steady_aim_i", PerkArchetype.BOWMAN, 1,
- new PerkBonus(PerkStat.RANGED_ACCURACY, 0.05D)));
- registerInternal(PerkNode.leaf("crossbowman/heavy_bolts_i", PerkArchetype.CROSSBOWMAN, 1,
- new PerkBonus(PerkStat.RANGED_VELOCITY, 0.1D)));
- registerInternal(PerkNode.leaf("pikeman/braced_stance_i", PerkArchetype.PIKEMAN, 1,
- new PerkBonus(PerkStat.KNOCKBACK_RESIST, 0.1D)));
- registerInternal(PerkNode.leaf("cavalry/swift_charge_i", PerkArchetype.CAVALRY, 1,
- new PerkBonus(PerkStat.MOVEMENT_SPEED, 0.01D)));
+ private static List defaultNodes() {
+ return List.of(
+ PerkNode.leaf("universal/toughness_i", PerkArchetype.UNIVERSAL, 1,
+ new PerkBonus(PerkStat.MAX_HEALTH, 2.0D)),
+ PerkNode.leaf("swordsman/iron_grip_i", PerkArchetype.SWORDSMAN, 1,
+ new PerkBonus(PerkStat.ATTACK_DAMAGE, 0.5D)),
+ PerkNode.leaf("bowman/steady_aim_i", PerkArchetype.BOWMAN, 1,
+ new PerkBonus(PerkStat.RANGED_ACCURACY, 0.05D)),
+ PerkNode.leaf("crossbowman/heavy_bolts_i", PerkArchetype.CROSSBOWMAN, 1,
+ new PerkBonus(PerkStat.RANGED_VELOCITY, 0.1D)),
+ PerkNode.leaf("pikeman/braced_stance_i", PerkArchetype.PIKEMAN, 1,
+ new PerkBonus(PerkStat.KNOCKBACK_RESIST, 0.1D)),
+ PerkNode.leaf("cavalry/swift_charge_i", PerkArchetype.CAVALRY, 1,
+ new PerkBonus(PerkStat.MOVEMENT_SPEED, 0.01D))
+ );
}
- private static void registerInternal(PerkNode node) {
- BY_ID.put(node.id(), node);
- BY_ARCHETYPE.get(node.archetype()).add(node);
- }
}
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/perks/PerkReloadListener.java b/src/main/java/com/talhanation/bannermod/entity/military/perks/PerkReloadListener.java
new file mode 100644
index 00000000..2fb83fe2
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/entity/military/perks/PerkReloadListener.java
@@ -0,0 +1,126 @@
+package com.talhanation.bannermod.entity.military.perks;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.talhanation.bannermod.bootstrap.BannerModMain;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.packs.resources.ResourceManager;
+import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
+import net.minecraft.util.profiling.ProfilerFiller;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public final class PerkReloadListener extends SimpleJsonResourceReloadListener {
+ private static final Gson GSON = new Gson();
+
+ public PerkReloadListener() {
+ super(GSON, "perks");
+ }
+
+ @Override
+ protected void apply(Map jsons, ResourceManager resourceManager, ProfilerFiller profiler) {
+ List nodes = new ArrayList<>();
+ Set ids = new HashSet<>();
+ for (Map.Entry entry : jsons.entrySet()) {
+ PerkNode node = parse(entry.getKey(), entry.getValue());
+ if (!ids.add(node.id())) {
+ throw new IllegalStateException("Duplicate perk id in datapack JSON: " + node.id());
+ }
+ nodes.add(node);
+ }
+
+ PerkRegistry.replaceAll(nodes);
+ BannerModMain.LOGGER.info("Loaded {} perks from datapacks", nodes.size());
+ }
+
+ private static PerkNode parse(ResourceLocation source, JsonElement json) {
+ if (!json.isJsonObject()) {
+ throw new JsonParseException("Perk " + source + " must be a JSON object");
+ }
+ JsonObject object = json.getAsJsonObject();
+ String id = requiredString(object, "id", source);
+ PerkArchetype archetype = enumValue(PerkArchetype.class, requiredString(object, "archetype", source), "archetype", source);
+ int pointCost = requiredInt(object, "point_cost", source);
+ List prerequisites = strings(object, "prerequisites", source);
+ List bonuses = bonuses(object, source);
+ return new PerkNode(id, archetype, pointCost, prerequisites, bonuses);
+ }
+
+ private static List bonuses(JsonObject object, ResourceLocation source) {
+ JsonArray array = requiredArray(object, "bonuses", source);
+ List bonuses = new ArrayList<>();
+ for (JsonElement element : array) {
+ if (!element.isJsonObject()) {
+ throw new JsonParseException("Perk " + source + " bonus entries must be objects");
+ }
+ JsonObject bonus = element.getAsJsonObject();
+ PerkStat stat = enumValue(PerkStat.class, requiredString(bonus, "stat", source), "stat", source);
+ double amount = requiredDouble(bonus, "amount", source);
+ bonuses.add(new PerkBonus(stat, amount));
+ }
+ return bonuses;
+ }
+
+ private static List strings(JsonObject object, String key, ResourceLocation source) {
+ JsonElement element = object.get(key);
+ if (element == null) return List.of();
+ if (!element.isJsonArray()) {
+ throw new JsonParseException("Perk " + source + " field '" + key + "' must be an array");
+ }
+ List values = new ArrayList<>();
+ for (JsonElement value : element.getAsJsonArray()) {
+ if (!value.isJsonPrimitive() || !value.getAsJsonPrimitive().isString()) {
+ throw new JsonParseException("Perk " + source + " field '" + key + "' must contain only strings");
+ }
+ values.add(value.getAsString());
+ }
+ return values;
+ }
+
+ private static String requiredString(JsonObject object, String key, ResourceLocation source) {
+ JsonElement element = object.get(key);
+ if (element == null || !element.isJsonPrimitive() || !element.getAsJsonPrimitive().isString()) {
+ throw new JsonParseException("Perk " + source + " requires string field '" + key + "'");
+ }
+ return element.getAsString();
+ }
+
+ private static int requiredInt(JsonObject object, String key, ResourceLocation source) {
+ JsonElement element = object.get(key);
+ if (element == null || !element.isJsonPrimitive() || !element.getAsJsonPrimitive().isNumber()) {
+ throw new JsonParseException("Perk " + source + " requires numeric field '" + key + "'");
+ }
+ return element.getAsInt();
+ }
+
+ private static double requiredDouble(JsonObject object, String key, ResourceLocation source) {
+ JsonElement element = object.get(key);
+ if (element == null || !element.isJsonPrimitive() || !element.getAsJsonPrimitive().isNumber()) {
+ throw new JsonParseException("Perk " + source + " requires numeric field '" + key + "'");
+ }
+ return element.getAsDouble();
+ }
+
+ private static JsonArray requiredArray(JsonObject object, String key, ResourceLocation source) {
+ JsonElement element = object.get(key);
+ if (element == null || !element.isJsonArray()) {
+ throw new JsonParseException("Perk " + source + " requires array field '" + key + "'");
+ }
+ return element.getAsJsonArray();
+ }
+
+ private static > T enumValue(Class type, String value, String key, ResourceLocation source) {
+ try {
+ return Enum.valueOf(type, value.toUpperCase(java.util.Locale.ROOT));
+ } catch (IllegalArgumentException ex) {
+ throw new JsonParseException("Perk " + source + " has invalid '" + key + "': " + value, ex);
+ }
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/perks/PlayerPerkProgressService.java b/src/main/java/com/talhanation/bannermod/entity/military/perks/PlayerPerkProgressService.java
new file mode 100644
index 00000000..90879242
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/entity/military/perks/PlayerPerkProgressService.java
@@ -0,0 +1,39 @@
+package com.talhanation.bannermod.entity.military.perks;
+
+import com.talhanation.bannermod.registry.ModAttachments;
+import net.minecraft.server.level.ServerPlayer;
+
+import java.util.Set;
+
+public final class PlayerPerkProgressService {
+ private static final int PERK_POINTS_PER_LEVEL = 1;
+
+ private PlayerPerkProgressService() {
+ }
+
+ public static PerkProgress progress(ServerPlayer player) {
+ return player.getData(ModAttachments.PLAYER_PERKS);
+ }
+
+ public static int availablePoints(ServerPlayer player) {
+ return progress(player).getAvailablePoints();
+ }
+
+ public static Set unlockedPerkIds(ServerPlayer player) {
+ return progress(player).getOwnedPerks();
+ }
+
+ public static void grantLevelPoints(ServerPlayer player, int gainedLevels) {
+ if (gainedLevels <= 0) return;
+ progress(player).grantPoints(gainedLevels * PERK_POINTS_PER_LEVEL);
+ }
+
+ public static PerkProgress.UnlockResult unlock(ServerPlayer player, String perkId) {
+ PerkNode node = PerkRegistry.get(perkId).orElse(null);
+ return progress(player).unlock(node);
+ }
+
+ public static int respec(ServerPlayer player) {
+ return progress(player).respec();
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/entity/military/runtime/DebugEvents.java b/src/main/java/com/talhanation/bannermod/entity/military/runtime/DebugEvents.java
index 27442a65..8b3d1a30 100644
--- a/src/main/java/com/talhanation/bannermod/entity/military/runtime/DebugEvents.java
+++ b/src/main/java/com/talhanation/bannermod/entity/military/runtime/DebugEvents.java
@@ -3,7 +3,6 @@
import com.talhanation.bannermod.config.RecruitsServerConfig;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.entity.military.ICompanion;
-import com.talhanation.bannermod.events.RecruitEvents;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
diff --git a/src/main/java/com/talhanation/bannermod/events/RecruitEvents.java b/src/main/java/com/talhanation/bannermod/entity/military/runtime/RecruitEvents.java
similarity index 92%
rename from src/main/java/com/talhanation/bannermod/events/RecruitEvents.java
rename to src/main/java/com/talhanation/bannermod/entity/military/runtime/RecruitEvents.java
index 5315794b..bebc6b51 100644
--- a/src/main/java/com/talhanation/bannermod/events/RecruitEvents.java
+++ b/src/main/java/com/talhanation/bannermod/entity/military/runtime/RecruitEvents.java
@@ -1,17 +1,16 @@
-package com.talhanation.bannermod.events;
-import com.talhanation.bannermod.bootstrap.BannerModMain;
+package com.talhanation.bannermod.entity.military.runtime;
+import com.talhanation.bannermod.bootstrap.BannerModMain;
import com.talhanation.bannermod.governance.BannerModGovernorPolicy;
import com.talhanation.bannermod.governance.runtime.RecruitGovernorWorkflow;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.entity.military.ICompanion;
+import com.talhanation.bannermod.api.event.RecruitEvent;
import com.talhanation.bannermod.registry.military.ModEntityTypes;
import com.talhanation.bannermod.inventory.military.PromoteContainer;
import com.talhanation.bannermod.network.messages.military.MessageOpenPromoteScreen;
import com.talhanation.bannermod.persistence.military.*;
-import com.talhanation.bannermod.events.RecruitEvent;
import com.talhanation.bannermod.combat.runtime.RecruitCombatRuntime;
-import com.talhanation.bannermod.entity.military.runtime.RecruitWorldLifecycleService;
import net.neoforged.neoforge.common.NeoForge;
import net.minecraft.network.chat.Component;
import net.minecraft.server.MinecraftServer;
@@ -31,8 +30,8 @@
import java.util.*;
public class RecruitEvents {
- static final Map RECRUIT_PATROL = new HashMap<>();
- static final Map PILLAGER_PATROL = new HashMap<>();
+ public static final Map RECRUIT_PATROL = new HashMap<>();
+ public static final Map PILLAGER_PATROL = new HashMap<>();
private static RecruitsPlayerUnitManager recruitsPlayerUnitManager;
private static RecruitsGroupsManager recruitsGroupsManager;
@@ -58,9 +57,9 @@ public static MinecraftServer server() {
return server;
}
- static void installRuntime(MinecraftServer currentServer,
- RecruitsPlayerUnitManager currentPlayerUnitManager,
- RecruitsGroupsManager currentGroupsManager) {
+ public static void installRuntime(MinecraftServer currentServer,
+ RecruitsPlayerUnitManager currentPlayerUnitManager,
+ RecruitsGroupsManager currentGroupsManager) {
server = currentServer;
recruitsPlayerUnitManager = currentPlayerUnitManager;
recruitsGroupsManager = currentGroupsManager;
diff --git a/src/main/java/com/talhanation/bannermod/events/AssassinEvents.java b/src/main/java/com/talhanation/bannermod/events/AssassinEvents.java
deleted file mode 100644
index e09d39a8..00000000
--- a/src/main/java/com/talhanation/bannermod/events/AssassinEvents.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package com.talhanation.bannermod.events;
-
-public class AssassinEvents {
- /*
- public static void createAssassin(String playerName, int count, Level world) {
- MinecraftServer server = world.getServer();
- PlayerList list = server.getPlayerList();
- Player target = list.getPlayerByName(playerName);
- BlockPos blockPos;
-
- if (target != null) {
- blockPos = calculateSpawnPos(target);
-
- while (!hasEnoughSpace(world, blockPos)){
- blockPos = calculateSpawnPos(target);
- }
- /*
- if (hasEnoughSpace(world, blockPos)){
- world.setBlock(blockPos, Blocks.REDSTONE_BLOCK.defaultBlockState(), 3);
- for (int i = 0; i < count; i++) {
- AssassinEntity assassin = ModEntityTypes.ASSASSIN.get().create(target.level);
- assassin.setPos(blockPos.getX(), blockPos.getY() + 1, blockPos.getZ());
- assassin.setEquipment();
- //assassin.setIsOwned(false);
- assassin.setIsInOrder(true);
- assassin.setDropEquipment();
- assassin.setPersistenceRequired();
- assassin.setCanPickUpLoot(true);
- assassin.setTarget(target);
- target.getCommandSenderWorld().addFreshEntity(assassin);
- }
- }
- }
-
- }
-
- private static BlockPos calculateSpawnPos(Player target){
- BlockPos blockPos = null;
-
-
- for(int i = 0; i < 10; ++i) {
- int d0 = (int) (target.getX() + (target.getCommandSenderWorld().random.nextInt(16) + 32));
- int d2 = (int) (target.getZ() + (target.getCommandSenderWorld().random.nextInt(16) + 32));
- int d1 = target.getCommandSenderWorld().getHeight(Heightmap.Types.WORLD_SURFACE, d0, d2);
-
-
- BlockPos blockpos1 = new BlockPos(d0, d1, d2);
-
- if (NaturalSpawner.isSpawnPositionOk(SpawnPlacements.Type.ON_GROUND, target.level, blockpos1, ModEntityTypes.ASSASSIN.get())) {
- blockPos = blockpos1;
- break;
- }
- }
- return blockPos;
- }
-
- private static boolean hasEnoughSpace(BlockGetter reader, BlockPos pos) {
- for(BlockPos blockpos : BlockPos.betweenClosed(pos, pos.offset(1, 2, 1))) {
- if (!reader.getBlockState(blockpos).getCollisionShape(reader, blockpos).isEmpty()) {
- return false;
- }
- }
-
- return true;
- }
-
- public static void doPayment(Player player, int costs){
- Inventory playerInv = player.getInventory();
- int playerEmeralds = 0;
- String str = RecruitsModConfig.RecruitCurrency.get();
- ItemStack currencyItemStack;
- Optional> holder = BuiltInRegistries.ITEM.getHolder(ResourceLocation.tryParse(str));
-
- if (holder.isPresent()){
- currencyItemStack = holder.get().value().getDefaultInstance();
- }
- else
- currencyItemStack = Items.EMERALD.getDefaultInstance();
-
- //checkPlayerMoney
- playerEmeralds = playerGetEmeraldsInInventory(player);
- //player.sendMessage(new TextComponent("PlayerEmeralds: " + playerEmeralds), player.getUUID());
- //player.sendMessage(new TextComponent("Costs: " + costs), player.getUUID());
- playerEmeralds = playerEmeralds - costs;
-
- //remove Player Emeralds
- for (int i = 0; i < playerInv.getContainerSize(); i++){
- ItemStack itemStackInSlot = playerInv.getItem(i);
- Item itemInSlot = itemStackInSlot.getItem();
- if (itemInSlot.equals(currencyItemStack)){
- playerInv.removeItemNoUpdate(i);
- }
- }
-
- //add Player Emeralds what is left
- ItemStack emeraldsLeft = Items.EMERALD.getDefaultInstance();
-
- emeraldsLeft.setCount(playerEmeralds);
- playerInv.add(emeraldsLeft);
- }
-
-
- public static int playerGetEmeraldsInInventory(Player player) {
- int emeralds = 0;
- Inventory playerInv = player.getInventory();
- for (int i = 0; i < playerInv.getContainerSize(); i++){
- ItemStack itemStackInSlot = playerInv.getItem(i);
- Item itemInSlot = itemStackInSlot.getItem();
- if (itemInSlot == Items.EMERALD){
- emeralds = emeralds + itemStackInSlot.getCount();
- }
- }
- return emeralds;
- }
-
- public static boolean playerHasEnoughEmeralds(Player player, int price) {
- int emeraldCount = AssassinEvents.playerGetEmeraldsInInventory(player);
- if (emeraldCount >= price){
- return true;
- }
- return player.isCreative();
- }
- */
-}
diff --git a/src/main/java/com/talhanation/bannermod/events/DamageEvent.java b/src/main/java/com/talhanation/bannermod/events/DamageEvent.java
index fed7221d..caa0a711 100644
--- a/src/main/java/com/talhanation/bannermod/events/DamageEvent.java
+++ b/src/main/java/com/talhanation/bannermod/events/DamageEvent.java
@@ -1,6 +1,7 @@
package com.talhanation.bannermod.events;
import com.talhanation.bannermod.config.RecruitsServerConfig;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
diff --git a/src/main/java/com/talhanation/bannermod/events/RecruitLifecycleEvents.java b/src/main/java/com/talhanation/bannermod/events/RecruitLifecycleEvents.java
index 54eecb7c..835cad2b 100644
--- a/src/main/java/com/talhanation/bannermod/events/RecruitLifecycleEvents.java
+++ b/src/main/java/com/talhanation/bannermod/events/RecruitLifecycleEvents.java
@@ -3,6 +3,7 @@
import com.talhanation.bannermod.ai.pathfinding.AsyncPathProcessor;
import com.talhanation.bannermod.ai.pathfinding.async.TrueAsyncPathfindingRuntime;
import com.talhanation.bannermod.entity.military.RecruitIndex;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.runtime.RecruitWorldLifecycleService;
import com.talhanation.bannermod.governance.runtime.RecruitGovernorWorkflow;
import com.talhanation.bannermod.util.FormationDimensionGuard;
diff --git a/src/main/java/com/talhanation/bannermod/events/WorkersCommandEvents.java b/src/main/java/com/talhanation/bannermod/events/WorkersCommandEvents.java
deleted file mode 100644
index 974960b8..00000000
--- a/src/main/java/com/talhanation/bannermod/events/WorkersCommandEvents.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.talhanation.bannermod.events;
-
-import com.talhanation.bannermod.entity.civilian.*;
-import net.minecraft.core.BlockPos;
-import net.minecraft.world.entity.LivingEntity;
-import net.minecraft.world.phys.AABB;
-
-import java.util.*;
-
-public class WorkersCommandEvents {
- public void setWorkArea(UUID player_uuid, AbstractWorkerEntity worker, AABB area) {
- LivingEntity owner = worker.getOwner();
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/events/civilian/SettlementWorkOrderClaimReleaseEvents.java b/src/main/java/com/talhanation/bannermod/events/civilian/SettlementWorkOrderClaimReleaseEvents.java
index c2a5a149..4d506ba9 100644
--- a/src/main/java/com/talhanation/bannermod/events/civilian/SettlementWorkOrderClaimReleaseEvents.java
+++ b/src/main/java/com/talhanation/bannermod/events/civilian/SettlementWorkOrderClaimReleaseEvents.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod.events.civilian;
import com.talhanation.bannermod.entity.civilian.AbstractWorkerEntity;
-import com.talhanation.bannermod.settlement.BannerModSettlementOrchestrator;
+import com.talhanation.bannermod.settlement.SettlementOrchestrator;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrder;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrderRuntime;
import net.minecraft.server.level.ServerLevel;
@@ -50,7 +50,7 @@ public void onWorkerLeave(EntityLeaveLevelEvent event) {
}
private static void releaseFor(ServerLevel serverLevel, UUID residentUuid) {
- SettlementWorkOrderRuntime runtime = BannerModSettlementOrchestrator.workOrderRuntime(serverLevel);
+ SettlementWorkOrderRuntime runtime = SettlementOrchestrator.workOrderRuntime(serverLevel);
if (runtime == null) return;
List released = runtime.releaseClaimsForResident(residentUuid);
if (!released.isEmpty()) {
diff --git a/src/main/java/com/talhanation/bannermod/governance/runtime/RecruitGovernorWorkflow.java b/src/main/java/com/talhanation/bannermod/governance/runtime/RecruitGovernorWorkflow.java
index b4ac3d2c..1d3217dd 100644
--- a/src/main/java/com/talhanation/bannermod/governance/runtime/RecruitGovernorWorkflow.java
+++ b/src/main/java/com/talhanation/bannermod/governance/runtime/RecruitGovernorWorkflow.java
@@ -15,9 +15,9 @@
import com.talhanation.bannermod.shared.settlement.BannerModSettlementClientSnapshotContract.Envelope;
import com.talhanation.bannermod.shared.settlement.BannerModSettlementClientSnapshotContract.Payload;
import com.talhanation.bannermod.shared.settlement.BannerModSettlementClientSnapshotContract.RefreshTrigger;
-import com.talhanation.bannermod.settlement.BannerModSettlementManager;
-import com.talhanation.bannermod.settlement.BannerModSettlementService;
-import com.talhanation.bannermod.settlement.BannerModSettlementSnapshot;
+import com.talhanation.bannermod.settlement.SettlementManager;
+import com.talhanation.bannermod.settlement.SettlementService;
+import com.talhanation.bannermod.settlement.SettlementSnapshot;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
@@ -52,10 +52,10 @@ public static boolean tryPromoteRecruit(AbstractRecruitEntity recruit, String na
if (result.allowed()) {
RecruitsClaim claim = resolveClaim(recruit);
if (claim != null) {
- BannerModSettlementService.refreshClaim(
+ SettlementService.refreshClaim(
serverLevel,
ClaimEvents.claimManager(),
- BannerModSettlementManager.get(serverLevel),
+ SettlementManager.get(serverLevel),
BannerModGovernorManager.get(serverLevel),
claim
);
@@ -93,7 +93,7 @@ public static void syncGovernorScreen(ServerPlayer player, AbstractRecruitEntity
Envelope envelope = Envelope.empty(0L, gameTime, RefreshTrigger.SCREEN_OPEN);
if (claim != null && recruit.getCommandSenderWorld() instanceof ServerLevel serverLevel) {
BannerModGovernorSnapshot governorSnapshot = governorService(serverLevel).getOrCreateGovernorSnapshot(claim);
- BannerModSettlementSnapshot settlementSnapshot = BannerModSettlementManager.get(serverLevel).getSnapshot(claim.getUUID());
+ SettlementSnapshot settlementSnapshot = SettlementManager.get(serverLevel).getSnapshot(claim.getUUID());
envelope = buildEnvelope(claim, settlementSnapshot, governorSnapshot, gameTime, RefreshTrigger.SCREEN_OPEN);
}
@@ -104,13 +104,13 @@ public static void syncGovernorScreen(ServerPlayer player, AbstractRecruitEntity
public static void syncGovernorSnapshotsOnLogin(ServerPlayer player) {
ServerLevel level = player.serverLevel();
BannerModGovernorManager governorManager = BannerModGovernorManager.get(level);
- BannerModSettlementManager settlementManager = BannerModSettlementManager.get(level);
+ SettlementManager settlementManager = SettlementManager.get(level);
long gameTime = level.getGameTime();
for (BannerModGovernorSnapshot governorSnapshot : governorManager.getAllSnapshots()) {
if (!player.getUUID().equals(governorSnapshot.governorOwnerUuid()) || governorSnapshot.governorRecruitUuid() == null) {
continue;
}
- BannerModSettlementSnapshot settlementSnapshot = settlementManager.getSnapshot(governorSnapshot.claimUuid());
+ SettlementSnapshot settlementSnapshot = settlementManager.getSnapshot(governorSnapshot.claimUuid());
Envelope envelope = buildEnvelope(governorSnapshot.claimUuid(), settlementSnapshot, governorSnapshot,
gameTime, RefreshTrigger.LOGIN);
sendGovernorUpdate(player, governorSnapshot.governorRecruitUuid(), envelope);
@@ -126,13 +126,13 @@ public static void syncGovernorMutationRefresh(ServerLevel level, RecruitsClaim
if (player == null) {
return;
}
- BannerModSettlementSnapshot settlementSnapshot = BannerModSettlementManager.get(level).getSnapshot(claim.getUUID());
+ SettlementSnapshot settlementSnapshot = SettlementManager.get(level).getSnapshot(claim.getUUID());
Envelope envelope = buildEnvelope(claim, settlementSnapshot, governorSnapshot, level.getGameTime(), RefreshTrigger.MUTATION_REFRESH);
sendGovernorUpdate(player, governorSnapshot.governorRecruitUuid(), envelope);
}
public static Envelope buildEnvelope(RecruitsClaim claim,
- BannerModSettlementSnapshot settlementSnapshot,
+ SettlementSnapshot settlementSnapshot,
BannerModGovernorSnapshot governorSnapshot,
long gameTime,
RefreshTrigger trigger) {
@@ -140,7 +140,7 @@ public static Envelope buildEnvelope(RecruitsClaim claim,
}
public static Envelope buildEnvelope(java.util.UUID claimUuid,
- BannerModSettlementSnapshot settlementSnapshot,
+ SettlementSnapshot settlementSnapshot,
BannerModGovernorSnapshot governorSnapshot,
long gameTime,
RefreshTrigger trigger) {
diff --git a/src/main/java/com/talhanation/bannermod/items/military/RecruitsSpawnEgg.java b/src/main/java/com/talhanation/bannermod/items/military/RecruitsSpawnEgg.java
index d86599e1..f9f6b325 100644
--- a/src/main/java/com/talhanation/bannermod/items/military/RecruitsSpawnEgg.java
+++ b/src/main/java/com/talhanation/bannermod/items/military/RecruitsSpawnEgg.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod.items.military;
import com.talhanation.bannermod.bootstrap.BannerModMain;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.component.DataComponents;
diff --git a/src/main/java/com/talhanation/bannermod/network/catalog/CivilianPacketCatalog.java b/src/main/java/com/talhanation/bannermod/network/catalog/CivilianPacketCatalog.java
index 39416d03..a203b36d 100644
--- a/src/main/java/com/talhanation/bannermod/network/catalog/CivilianPacketCatalog.java
+++ b/src/main/java/com/talhanation/bannermod/network/catalog/CivilianPacketCatalog.java
@@ -40,6 +40,7 @@ public final class CivilianPacketCatalog {
MessageReassignWorkerProfession.class,
MessageAssignCitizenVacancy.class,
MessageAssignHome.class,
+ MessageDismissWorker.class,
};
public static final PacketCatalog CATALOG = new PacketCatalog(MESSAGES);
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageAssignHome.java b/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageAssignHome.java
index da7a7a58..4ce6bbcc 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageAssignHome.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageAssignHome.java
@@ -6,6 +6,11 @@
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import com.talhanation.bannermod.network.payload.BannerModMessage;
+import com.talhanation.bannermod.settlement.building.BuildingValidationState;
+import com.talhanation.bannermod.settlement.building.ValidatedBuildingRecord;
+import com.talhanation.bannermod.settlement.building.ValidatedBuildingRegistryData;
+import com.talhanation.bannermod.settlement.building.ZoneRole;
+import com.talhanation.bannermod.settlement.building.ZoneSelection;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
@@ -13,13 +18,12 @@
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
-import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.BedBlock;
import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.phys.AABB;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import java.util.Objects;
import java.util.UUID;
/**
@@ -68,7 +72,8 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer sender = Objects.requireNonNull(context.getSender(), "sender required for MessageAssignHome");
+ ServerPlayer sender = context.getSender();
+ if (sender == null) return;
handle(sender, this.entityUuid, this.pos);
});
}
@@ -144,14 +149,25 @@ private static UUID ownerOf(Entity entity) {
return null;
}
- /**
- * A "valid" home is currently a vanilla {@link BedBlock}. HousePrefab build
- * area validation is intentionally out-of-scope for this slice; HOMEASSIGN-002
- * only requires bed/sleeping-zone acceptance and the bed path is universal.
- */
+ /** A valid home is a vanilla bed or a server-registered valid sleeping zone. */
public static boolean isValidHomeTarget(ServerLevel level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
- return state.getBlock() instanceof BedBlock;
+ return state.getBlock() instanceof BedBlock || isValidatedSleepingZone(level, pos);
+ }
+
+ private static boolean isValidatedSleepingZone(ServerLevel level, BlockPos pos) {
+ AABB pointBounds = new AABB(pos);
+ for (ValidatedBuildingRecord record : ValidatedBuildingRegistryData.get(level).findIntersecting(pointBounds)) {
+ if (record.state() != BuildingValidationState.VALID || !level.dimension().equals(record.dimension())) {
+ continue;
+ }
+ for (ZoneSelection zone : record.zones()) {
+ if (zone.role() == ZoneRole.SLEEPING && zone.contains(pos)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
@Override
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageDismissWorker.java b/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageDismissWorker.java
new file mode 100644
index 00000000..1504bb9c
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageDismissWorker.java
@@ -0,0 +1,61 @@
+package com.talhanation.bannermod.network.messages.civilian;
+
+import com.talhanation.bannermod.entity.civilian.AbstractWorkerEntity;
+import com.talhanation.bannermod.entity.civilian.WorkerDismissService;
+import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
+import com.talhanation.bannermod.network.payload.BannerModMessage;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.protocol.PacketFlow;
+import net.minecraft.server.level.ServerPlayer;
+
+import java.util.UUID;
+
+public class MessageDismissWorker implements BannerModMessage {
+ private UUID workerUuid;
+
+ public MessageDismissWorker() {
+ }
+
+ public MessageDismissWorker(UUID workerUuid) {
+ this.workerUuid = workerUuid;
+ }
+
+ @Override
+ public PacketFlow getExecutingSide() {
+ return BannerModMessage.serverbound();
+ }
+
+ @Override
+ public void executeServerSide(BannerModNetworkContext context) {
+ context.enqueueWork(() -> {
+ ServerPlayer player = context.getSender();
+ if (player == null || this.workerUuid == null) {
+ return;
+ }
+ if (!(player.serverLevel().getEntity(this.workerUuid) instanceof AbstractWorkerEntity worker)) {
+ player.sendSystemMessage(Component.translatable("chat.bannermod.workerui.dismiss.denied.missing"));
+ return;
+ }
+ String denialKey = WorkerDismissService.dismissDeniedReasonKey(player, worker);
+ if (denialKey != null) {
+ player.sendSystemMessage(Component.translatable(denialKey));
+ return;
+ }
+ if (WorkerDismissService.dismiss(player, worker)) {
+ player.sendSystemMessage(Component.translatable("chat.bannermod.workerui.dismiss.success"));
+ }
+ });
+ }
+
+ @Override
+ public MessageDismissWorker fromBytes(FriendlyByteBuf buf) {
+ this.workerUuid = buf.readUUID();
+ return this;
+ }
+
+ @Override
+ public void toBytes(FriendlyByteBuf buf) {
+ buf.writeUUID(this.workerUuid);
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageOpenMerchantEditTradeScreen.java b/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageOpenMerchantEditTradeScreen.java
index eebbde92..90aad2d9 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageOpenMerchantEditTradeScreen.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageOpenMerchantEditTradeScreen.java
@@ -34,10 +34,11 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- if (!context.getSender().getUUID().equals(player)) {
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
+ if (!player.getUUID().equals(this.player)) {
return;
}
- ServerPlayer player = context.getSender();
Entity entity = player.serverLevel().getEntity(this.merchantUuid);
if (entity instanceof MerchantEntity merchant
&& merchant.isAlive()
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageOpenMerchantTradeScreen.java b/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageOpenMerchantTradeScreen.java
index 427afe3b..e3ca5b89 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageOpenMerchantTradeScreen.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageOpenMerchantTradeScreen.java
@@ -31,6 +31,7 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
ServerPlayer player = context.getSender();
+ if (player == null) return;
Entity entity = player.serverLevel().getEntity(this.merchantUuid);
if (entity instanceof MerchantEntity merchant
&& merchant.isAlive()
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageUpdateStorageArea.java b/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageUpdateStorageArea.java
index af4f4469..a91212fa 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageUpdateStorageArea.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/civilian/MessageUpdateStorageArea.java
@@ -4,8 +4,8 @@
import com.talhanation.bannermod.governance.BannerModGovernorManager;
import com.talhanation.bannermod.entity.civilian.workarea.StorageArea;
import com.talhanation.bannermod.shared.logistics.BannerModLogisticsAuthoringState;
-import com.talhanation.bannermod.settlement.BannerModSettlementManager;
-import com.talhanation.bannermod.settlement.BannerModSettlementService;
+import com.talhanation.bannermod.settlement.SettlementManager;
+import com.talhanation.bannermod.settlement.SettlementService;
import com.talhanation.bannermod.network.payload.BannerModMessage;
import net.minecraft.network.protocol.PacketFlow;
import net.minecraft.network.FriendlyByteBuf;
@@ -71,10 +71,10 @@ public void update(StorageArea storageArea, ServerPlayer player){
}
if (player.level() instanceof ServerLevel serverLevel && ClaimEvents.claimManager() != null) {
- BannerModSettlementService.refreshClaimAt(
+ SettlementService.refreshClaimAt(
serverLevel,
ClaimEvents.claimManager(),
- BannerModSettlementManager.get(serverLevel),
+ SettlementManager.get(serverLevel),
BannerModGovernorManager.get(serverLevel),
storageArea.blockPosition()
);
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAdminRecruitSpawn.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAdminRecruitSpawn.java
index cf8627d8..da17f75f 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAdminRecruitSpawn.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAdminRecruitSpawn.java
@@ -16,7 +16,6 @@
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MobSpawnType;
-import java.util.Objects;
public class MessageAdminRecruitSpawn implements BannerModMessage {
private String entityId;
@@ -39,7 +38,8 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
if (!player.hasPermissions(2) || !player.isCreative()) {
return;
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAggro.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAggro.java
index d9311a78..f7ca2247 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAggro.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAggro.java
@@ -15,7 +15,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageAggro implements BannerModMessage {
@@ -44,7 +43,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
double boundBoxInflateModifier = fromGui ? 16.0D : 100.0D;
AABB commandBox = player.getBoundingBox().inflate(boundBoxInflateModifier);
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAggroGui.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAggroGui.java
index e914059a..bae83190 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAggroGui.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAggroGui.java
@@ -8,7 +8,6 @@
import net.minecraft.server.level.ServerPlayer;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageAggroGui implements BannerModMessage {
@@ -30,7 +29,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
AbstractRecruitEntity recruit = RecruitMessageEntityResolver.resolveRecruitInInflatedBox(player, this.uuid, 16.0D);
if (RecruitCommandAuthority.canDirectlyControl(player, recruit)) {
recruit.setAggroState(this.state);
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAnswerMessenger.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAnswerMessenger.java
index 852d26be..9b870467 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAnswerMessenger.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAnswerMessenger.java
@@ -8,7 +8,6 @@
import net.minecraft.world.entity.Entity;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageAnswerMessenger implements BannerModMessage {
@@ -26,7 +25,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context){
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
Entity entity = player.serverLevel().getEntity(this.recruit);
if (entity instanceof MessengerEntity messenger && messenger.distanceToSqr(player) <= 16D * 16D) {
messenger.teleportWaitTimer = 100;
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageApplyNoGroup.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageApplyNoGroup.java
index 30a4d282..64e04cff 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageApplyNoGroup.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageApplyNoGroup.java
@@ -31,7 +31,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
List recruitList = new ArrayList<>();
ServerLevel serverLevel = (ServerLevel) player.getCommandSenderWorld();
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssassinCount.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssassinCount.java
index 31522d4a..168b6cc0 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssassinCount.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssassinCount.java
@@ -8,7 +8,6 @@
import net.minecraft.world.entity.Entity;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageAssassinCount implements BannerModMessage {
@@ -30,12 +29,12 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context){
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
Entity entity = player.serverLevel().getEntity(this.uuid);
if (entity instanceof AssassinLeaderEntity leader
- && (leader.isControlledBy(player) || player.hasPermissions(2))
&& player.getBoundingBox().inflate(16.0D).intersects(leader.getBoundingBox())) {
- leader.setCount(this.count);
+ leader.trySetCountFrom(player.getUUID(), player.hasPermissions(2), this.count);
}
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssassinGui.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssassinGui.java
index 2df8ab4c..d388323a 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssassinGui.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssassinGui.java
@@ -9,7 +9,6 @@
import net.minecraft.network.FriendlyByteBuf;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageAssassinGui implements BannerModMessage {
@@ -35,7 +34,8 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
if (!player.getUUID().equals(uuid)) {
return;
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssassinate.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssassinate.java
index dcca3382..b606b3e6 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssassinate.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssassinate.java
@@ -11,7 +11,6 @@
import net.minecraft.server.players.PlayerList;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
public class MessageAssassinate implements BannerModMessage {
@@ -36,7 +35,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
ServerLevel world = player.serverLevel();
MinecraftServer server = world.getServer();
PlayerList list = server.getPlayerList();
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignGroupToCompanion.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignGroupToCompanion.java
index 55c1ff04..362d1364 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignGroupToCompanion.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignGroupToCompanion.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod.network.messages.military;
import com.talhanation.bannermod.army.command.RecruitCommandAuthority;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractLeaderEntity;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.entity.military.ICompanion;
@@ -20,7 +20,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageAssignGroupToCompanion implements BannerModMessage {
@@ -41,7 +40,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer serverPlayer = Objects.requireNonNull(context.getSender());
+ ServerPlayer serverPlayer = context.getSender();
+ if (serverPlayer == null) return;
ServerLevel serverLevel = serverPlayer.serverLevel();
Entity entity = serverLevel.getEntity(this.companionUUID);
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignGroupToPlayer.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignGroupToPlayer.java
index 61eddbf0..75f92eb3 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignGroupToPlayer.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignGroupToPlayer.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod.network.messages.military;
import com.talhanation.bannermod.army.command.RecruitCommandAuthority;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.entity.military.RecruitIndex;
import com.talhanation.bannermod.persistence.military.RecruitsGroup;
@@ -20,7 +20,6 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
-import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
@@ -47,7 +46,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
RecruitsPlayerInfo newOwner = RecruitsPlayerInfo.getFromNBT(tag);
transferGroupToPlayer(player, groupUUID, newOwner);
});
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignNearbyRecruitsInGroup.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignNearbyRecruitsInGroup.java
index e957ca9c..191c1ada 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignNearbyRecruitsInGroup.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignNearbyRecruitsInGroup.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.network.messages.military;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.entity.military.RecruitIndex;
import com.talhanation.bannermod.persistence.military.RecruitsGroup;
@@ -12,7 +12,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageAssignNearbyRecruitsInGroup implements BannerModMessage {
@@ -32,7 +31,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
RecruitsGroup newGroup = RecruitEvents.groupsManager().getGroup(groupUUID);
if(newGroup == null) return;
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignRecruitToPlayer.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignRecruitToPlayer.java
index 73b09019..864eb83b 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignRecruitToPlayer.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAssignRecruitToPlayer.java
@@ -8,7 +8,6 @@
import net.minecraft.server.level.ServerPlayer;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageAssignRecruitToPlayer implements BannerModMessage {
@@ -29,7 +28,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer serverPlayer = Objects.requireNonNull(context.getSender());
+ ServerPlayer serverPlayer = context.getSender();
+ if (serverPlayer == null) return;
AbstractRecruitEntity recruit = RecruitMessageEntityResolver.resolveRecruitInInflatedBox(serverPlayer, this.recruit, 64.0D);
assignRecruitToPlayer(serverPlayer, recruit, newOwner);
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAttack.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAttack.java
index d6b2b3ce..ae1008ac 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAttack.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageAttack.java
@@ -16,7 +16,6 @@
import java.util.HashSet;
import java.util.List;
-import java.util.Objects;
import java.util.Set;
import java.util.UUID;
@@ -38,7 +37,8 @@ public PacketFlow getExecutingSide() {
}
public void executeServerSide(BannerModNetworkContext context) {
- ServerPlayer serverPlayer = Objects.requireNonNull(context.getSender());
+ ServerPlayer serverPlayer = context.getSender();
+ if (serverPlayer == null) return;
if (!com.talhanation.bannermod.network.throttle.PacketRateLimiter.shared()
.tryAcquire(serverPlayer.getUUID(), MessageAttack.class)) {
RuntimeProfilingCounters.increment("network.rate_limit.dropped.attack");
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageBackToMountEntity.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageBackToMountEntity.java
index 1dab8b6f..4eb5f287 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageBackToMountEntity.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageBackToMountEntity.java
@@ -13,7 +13,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageBackToMountEntity implements BannerModMessage {
@@ -36,7 +35,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
UUID actorUuid = authorizedPlayerUuid(player.getUUID(), this.uuid);
List recruits = this.group == null
? RecruitIndex.instance().ownerInRange(player.getCommandSenderWorld(), actorUuid, player.position(), 100.0D)
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearTarget.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearTarget.java
index a4a5164a..e4e1837c 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearTarget.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearTarget.java
@@ -9,7 +9,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageClearTarget implements BannerModMessage {
@@ -31,7 +30,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context){
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
dispatchToServer(player, this.uuid, this.group);
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearTargetGui.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearTargetGui.java
index eb7799e1..4333047c 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearTargetGui.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearTargetGui.java
@@ -9,7 +9,6 @@
import net.minecraft.server.level.ServerPlayer;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageClearTargetGui implements BannerModMessage {
@@ -30,7 +29,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
AbstractRecruitEntity recruit = RecruitMessageEntityResolver.resolveRecruitInInflatedBox(player, this.recruit, 16.0D);
if (recruit != null && RecruitCommandAuthority.canDirectlyControl(player, recruit)) {
CommandEvents.onClearTargetButton(recruit.getOwnerUUID(), recruit, null);
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearUpkeep.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearUpkeep.java
index cef77ec3..3f41685a 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearUpkeep.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearUpkeep.java
@@ -11,7 +11,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageClearUpkeep implements BannerModMessage {
@@ -32,7 +31,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
UUID actorUuid = authorizedPlayerUuid(player.getUUID(), this.uuid);
List recruits = this.group == null
? RecruitIndex.instance().ownerInRange(player.getCommandSenderWorld(), actorUuid, player.position(), 100.0D)
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearUpkeepGui.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearUpkeepGui.java
index 3defa5a9..9c1dd564 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearUpkeepGui.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageClearUpkeepGui.java
@@ -7,7 +7,6 @@
import net.minecraft.server.level.ServerPlayer;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageClearUpkeepGui implements BannerModMessage {
@@ -27,7 +26,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context){
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
AbstractRecruitEntity recruit = RecruitMessageEntityResolver.resolveRecruitInInflatedBox(player, this.uuid, 16.0D);
if (recruit != null) {
recruit.clearUpkeepPos();
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageCombatStance.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageCombatStance.java
index 50113d44..233d1f88 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageCombatStance.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageCombatStance.java
@@ -18,7 +18,6 @@
import java.util.HashSet;
import java.util.List;
-import java.util.Objects;
import java.util.Set;
import java.util.UUID;
@@ -42,7 +41,8 @@ public PacketFlow getExecutingSide() {
}
public void executeServerSide(BannerModNetworkContext context) {
- ServerPlayer sender = Objects.requireNonNull(context.getSender());
+ ServerPlayer sender = context.getSender();
+ if (sender == null) return;
if (!com.talhanation.bannermod.network.throttle.PacketRateLimiter.shared()
.tryAcquire(sender.getUUID(), MessageCombatStance.class)) {
RuntimeProfilingCounters.increment("network.rate_limit.dropped.stance");
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageCombatStanceGui.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageCombatStanceGui.java
index b64f10c1..ec40cc19 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageCombatStanceGui.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageCombatStanceGui.java
@@ -10,7 +10,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageCombatStanceGui implements BannerModMessage {
@@ -36,7 +35,8 @@ public void executeServerSide(BannerModNetworkContext context) {
return;
}
- ServerPlayer serverPlayer = Objects.requireNonNull(context.getSender());
+ ServerPlayer serverPlayer = context.getSender();
+ if (serverPlayer == null) return;
AbstractRecruitEntity recruit = RecruitMessageEntityResolver.resolveRecruitInInflatedBox(serverPlayer, this.recruitUuid, 16.0D);
if (recruit == null) {
return;
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageCommandScreen.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageCommandScreen.java
index 56159dc0..6f59c2b3 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageCommandScreen.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageCommandScreen.java
@@ -31,6 +31,7 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
ServerPlayer player = context.getSender();
+ if (player == null) return;
if (!player.getUUID().equals(uuid)) {
return;
}
@@ -49,4 +50,4 @@ public void toBytes(FriendlyByteBuf buf) {
buf.writeUUID(uuid);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDebugGui.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDebugGui.java
index 9e6647d2..9f0d7971 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDebugGui.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDebugGui.java
@@ -12,7 +12,6 @@
import net.minecraft.server.level.ServerPlayer;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageDebugGui implements BannerModMessage {
@@ -36,14 +35,15 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
AbstractRecruitEntity recruit = RecruitMessageEntityResolver.resolveRecruitInInflatedBox(player, this.uuid, 16.0D);
if (recruit != null) {
if (!shouldHandleDebugMessage(id, player, recruit)) {
return;
}
- DebugEvents.handleMessage(id, recruit, context.getSender());
+ DebugEvents.handleMessage(id, recruit, player);
recruit.setCustomName(Component.literal(name));
}
});
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDebugScreen.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDebugScreen.java
index c3ca9313..2edc2fee 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDebugScreen.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDebugScreen.java
@@ -8,7 +8,6 @@
import net.minecraft.world.entity.player.Player;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageDebugScreen implements BannerModMessage {
@@ -33,7 +32,8 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
if (!player.getUUID().equals(uuid)) {
return;
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDisband.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDisband.java
index fd06eb18..5d0253ec 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDisband.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDisband.java
@@ -8,7 +8,6 @@
import net.minecraft.server.level.ServerPlayer;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageDisband implements BannerModMessage {
@@ -30,10 +29,11 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
AbstractRecruitEntity recruit = RecruitMessageEntityResolver.resolveRecruitInInflatedBox(player, this.recruit, 16D);
if (RecruitCommandAuthority.canDirectlyControl(player, recruit)) {
- recruit.disband(context.getSender(), keepTeam, true);
+ recruit.disband(player, keepTeam, true);
}
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDisbandGroup.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDisbandGroup.java
index ded7a2a6..08af3ffb 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDisbandGroup.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDisbandGroup.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.network.messages.military;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.entity.military.RecruitIndex;
import com.talhanation.bannermod.persistence.military.RecruitsGroup;
@@ -13,7 +13,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageDisbandGroup implements BannerModMessage {
@@ -37,7 +36,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
RecruitsGroup group = RecruitEvents.groupsManager().getGroup(groupUUID);
if(group == null) return;
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDismount.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDismount.java
index da947553..5b08e1d1 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDismount.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDismount.java
@@ -9,7 +9,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageDismount implements BannerModMessage {
@@ -32,7 +31,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context){
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
dispatchToServer(player, this.uuid, this.group);
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDismountGui.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDismountGui.java
index 8f870f21..a6a94c14 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDismountGui.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageDismountGui.java
@@ -9,7 +9,6 @@
import net.minecraft.server.level.ServerPlayer;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageDismountGui implements BannerModMessage {
@@ -31,7 +30,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer serverPlayer = Objects.requireNonNull(context.getSender());
+ ServerPlayer serverPlayer = context.getSender();
+ if (serverPlayer == null) return;
AbstractRecruitEntity recruit = RecruitMessageEntityResolver.resolveRecruitInInflatedBox(serverPlayer, this.uuid, 16.0D);
if (recruit != null && RecruitCommandAuthority.canDirectlyControl(serverPlayer, recruit)) {
CommandEvents.onDismountButton(recruit.getOwnerUUID(), recruit, null);
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageFaceCommand.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageFaceCommand.java
index 04deae80..8309279e 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageFaceCommand.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageFaceCommand.java
@@ -14,7 +14,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageFaceCommand implements BannerModMessage {
@@ -39,7 +38,8 @@ public PacketFlow getExecutingSide() {
}
public void executeServerSide(BannerModNetworkContext context){
- ServerPlayer sender = Objects.requireNonNull(context.getSender());
+ ServerPlayer sender = context.getSender();
+ if (sender == null) return;
if (!com.talhanation.bannermod.network.throttle.PacketRateLimiter.shared()
.tryAcquire(sender.getUUID(), MessageFaceCommand.class)) {
RuntimeProfilingCounters.increment("network.rate_limit.dropped.face");
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageFollowGui.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageFollowGui.java
index 3a601873..3c6e7cc8 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageFollowGui.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageFollowGui.java
@@ -11,7 +11,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageFollowGui implements BannerModMessage {
@@ -33,7 +32,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer serverPlayer = Objects.requireNonNull(context.getSender());
+ ServerPlayer serverPlayer = context.getSender();
+ if (serverPlayer == null) return;
dispatchToServer(serverPlayer, this.uuid, this.state);
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageFormationFollowMovement.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageFormationFollowMovement.java
index 264841c0..3310a7ca 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageFormationFollowMovement.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageFormationFollowMovement.java
@@ -8,11 +8,11 @@
import com.talhanation.bannermod.network.payload.BannerModMessage;
import net.minecraft.network.protocol.PacketFlow;
import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
import java.util.HashSet;
import java.util.Set;
@@ -39,7 +39,10 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context){
context.enqueueWork(() -> {
- dispatchToServer(Objects.requireNonNull(context.getSender()), this.player_uuid, this.group, this.formation);
+ ServerPlayer sender = context.getSender();
+ if (sender == null) return;
+
+ dispatchToServer(sender, this.player_uuid, this.group, this.formation);
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageGroup.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageGroup.java
index 998a2ec8..6646c857 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageGroup.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageGroup.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod.network.messages.military;
import com.talhanation.bannermod.army.command.RecruitCommandAuthority;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.persistence.military.RecruitsGroup;
import com.talhanation.bannermod.network.payload.BannerModMessage;
@@ -10,7 +10,6 @@
import net.minecraft.server.level.ServerPlayer;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageGroup implements BannerModMessage {
@@ -32,7 +31,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
AbstractRecruitEntity recruit = RecruitMessageEntityResolver.resolveRecruitInInflatedBox(player, this.recruitUUID, 100.0D);
if (RecruitCommandAuthority.canDirectlyControl(player, recruit)) {
this.setGroup(recruit, player, groupUUID);
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageHire.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageHire.java
index 6e4b9d53..bce4bee1 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageHire.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageHire.java
@@ -10,7 +10,6 @@
import net.minecraft.server.level.ServerPlayer;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageHire implements BannerModMessage {
@@ -34,7 +33,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
RecruitsGroup group = RecruitCommandAuthority.ownedGroup(player, groupUUID);
AbstractRecruitEntity recruit = RecruitMessageEntityResolver.resolveRecruitWithinDistance(player, this.recruit, 16.0D * 16.0D);
if (recruit != null) {
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageHireFromNobleVillager.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageHireFromNobleVillager.java
index ae7ccad2..5da51157 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageHireFromNobleVillager.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageHireFromNobleVillager.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod.network.messages.military;
import com.talhanation.bannermod.bootstrap.BannerModMain;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.entity.military.VillagerNobleEntity;
import com.talhanation.bannermod.entity.military.runtime.VillagerConversionService;
@@ -20,7 +20,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import com.talhanation.bannermod.network.compat.BannerModPacketDistributor;
-import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
@@ -58,7 +57,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
ServerLevel serverLevel = player.serverLevel();
Entity nobleEntity = serverLevel.getEntity(this.nobleUUID);
if (!(nobleEntity instanceof VillagerNobleEntity villagerNoble)
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageHireGui.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageHireGui.java
index 02ffc5ec..80c437ff 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageHireGui.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageHireGui.java
@@ -8,7 +8,6 @@
import net.minecraft.world.entity.player.Player;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageHireGui implements BannerModMessage {
@@ -34,7 +33,8 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
if (!player.getUUID().equals(uuid)) {
return;
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageListen.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageListen.java
index 8cdf988b..dfdf66fe 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageListen.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageListen.java
@@ -8,7 +8,6 @@
import net.minecraft.server.level.ServerPlayer;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageListen implements BannerModMessage {
@@ -30,7 +29,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
AbstractRecruitEntity recruit = RecruitMessageEntityResolver.resolveRecruitInInflatedBox(player, this.uuid, 100.0D);
if (RecruitCommandAuthority.canDirectlyControl(player, recruit)) {
recruit.setListen(bool);
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMergeGroup.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMergeGroup.java
index 1989a7b0..f87baf4a 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMergeGroup.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMergeGroup.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.network.messages.military;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.persistence.military.RecruitsGroup;
import com.talhanation.bannermod.network.payload.BannerModMessage;
@@ -10,7 +10,6 @@
import net.minecraft.server.level.ServerPlayer;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageMergeGroup implements BannerModMessage {
@@ -32,7 +31,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
RecruitsGroup groupToMerge = RecruitEvents.groupsManager().getGroup(mergeUUID);
RecruitsGroup baseGroup = RecruitEvents.groupsManager().getGroup(groupUUID);
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMountEntity.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMountEntity.java
index abcc2a63..1de50b76 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMountEntity.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMountEntity.java
@@ -15,7 +15,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageMountEntity implements BannerModMessage {
@@ -39,7 +38,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
Entity mount = player.serverLevel().getEntity(target);
if (mount == null
|| mount.distanceToSqr(player) > 100.0D * 100.0D
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMountEntityGui.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMountEntityGui.java
index 74722791..bc02b650 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMountEntityGui.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMountEntityGui.java
@@ -40,7 +40,8 @@ public PacketFlow getExecutingSide() {
@SuppressWarnings({"all"})
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
AbstractRecruitEntity recruit = RecruitMessageEntityResolver.resolveRecruitWithinDistance(player, this.recruit, 32.0D * 32.0D);
if (recruit != null) {
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMovement.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMovement.java
index 3d3aa74a..3bf12d70 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMovement.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageMovement.java
@@ -15,7 +15,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
import java.util.HashSet;
import java.util.Set;
@@ -44,14 +43,15 @@ public PacketFlow getExecutingSide() {
}
public void executeServerSide(BannerModNetworkContext context){
- ServerPlayer sender = Objects.requireNonNull(context.getSender());
+ ServerPlayer sender = context.getSender();
+ if (sender == null) return;
if (!com.talhanation.bannermod.network.throttle.PacketRateLimiter.shared()
.tryAcquire(sender.getUUID(), MessageMovement.class)) {
RuntimeProfilingCounters.increment("network.rate_limit.dropped.movement");
return;
}
context.enqueueWork(() -> {
- dispatchToServer(Objects.requireNonNull(context.getSender()), this.player_uuid, this.group, this.state, this.formation, this.tight);
+ dispatchToServer(sender, this.player_uuid, this.group, this.state, this.formation, this.tight);
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenDisbandScreen.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenDisbandScreen.java
index c3a8774d..844c2609 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenDisbandScreen.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenDisbandScreen.java
@@ -32,6 +32,7 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
ServerPlayer player = context.getSender();
+ if (player == null) return;
if (!player.getUUID().equals(this.player)) {
return;
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenGovernorScreen.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenGovernorScreen.java
index 8578e7bb..70161626 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenGovernorScreen.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenGovernorScreen.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.network.messages.military;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.network.payload.BannerModMessage;
import net.minecraft.network.protocol.PacketFlow;
@@ -8,7 +8,6 @@
import net.minecraft.server.level.ServerPlayer;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageOpenGovernorScreen implements BannerModMessage {
@@ -31,7 +30,8 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
AbstractRecruitEntity recruitEntity = RecruitMessageEntityResolver.resolveRecruitInInflatedBox(player, this.recruit, 16.0D);
if (recruitEntity != null) {
if (this.openMenu) {
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenPromoteScreen.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenPromoteScreen.java
index d4c66658..1e9dfc6c 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenPromoteScreen.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenPromoteScreen.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.network.messages.military;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.network.payload.BannerModMessage;
import net.minecraft.network.protocol.PacketFlow;
@@ -9,7 +9,6 @@
import net.minecraft.world.entity.player.Player;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageOpenPromoteScreen implements BannerModMessage {
@@ -34,7 +33,8 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
if (!player.getUUID().equals(this.player)) {
return;
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenSpecialScreen.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenSpecialScreen.java
index 283376eb..fee2bca2 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenSpecialScreen.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageOpenSpecialScreen.java
@@ -10,7 +10,6 @@
import net.minecraft.world.entity.player.Player;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageOpenSpecialScreen implements BannerModMessage {
@@ -35,7 +34,8 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
if (!player.getUUID().equals(this.player)) {
return;
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderAddWayPoint.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderAddWayPoint.java
index 9a771525..783ef135 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderAddWayPoint.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderAddWayPoint.java
@@ -20,7 +20,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import com.talhanation.bannermod.network.compat.BannerModPacketDistributor;
-import java.util.Objects;
import java.util.UUID;
public class MessagePatrolLeaderAddWayPoint implements BannerModMessage {
@@ -45,7 +44,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
Entity entity = player.serverLevel().getEntity(this.worker);
if (entity instanceof AbstractLeaderEntity leader
&& leader.isAlive()
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderRemoveWayPoint.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderRemoveWayPoint.java
index 1b1bd578..7d5c54c5 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderRemoveWayPoint.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderRemoveWayPoint.java
@@ -13,7 +13,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import com.talhanation.bannermod.network.compat.BannerModPacketDistributor;
-import java.util.Objects;
import java.util.UUID;
public class MessagePatrolLeaderRemoveWayPoint implements BannerModMessage {
@@ -32,7 +31,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
Entity entity = player.serverLevel().getEntity(this.worker);
if (entity instanceof AbstractLeaderEntity leader
&& leader.isAlive()
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetCycle.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetCycle.java
index c2902fbd..5dadad8a 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetCycle.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetCycle.java
@@ -9,7 +9,6 @@
import net.minecraft.world.entity.Entity;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
@@ -32,7 +31,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
Entity entity = player.serverLevel().getEntity(this.recruit);
if (entity instanceof AbstractLeaderEntity leader
&& RecruitCommandAuthority.canDirectlyControl(player, leader)
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetEnemyAction.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetEnemyAction.java
index 6ffd37d8..13db62f7 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetEnemyAction.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetEnemyAction.java
@@ -9,7 +9,6 @@
import net.minecraft.world.entity.Entity;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessagePatrolLeaderSetEnemyAction implements BannerModMessage {
@@ -30,7 +29,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
Entity entity = player.serverLevel().getEntity(this.recruit);
if (entity instanceof AbstractLeaderEntity leader
&& leader.isAlive()
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetInfoMode.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetInfoMode.java
index 045b12e5..9174a6ea 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetInfoMode.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetInfoMode.java
@@ -9,7 +9,6 @@
import net.minecraft.world.entity.Entity;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessagePatrolLeaderSetInfoMode implements BannerModMessage {
@@ -30,7 +29,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
Entity entity = player.serverLevel().getEntity(this.recruit);
if (entity instanceof AbstractLeaderEntity leader
&& leader.isAlive()
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetPatrolState.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetPatrolState.java
index 0bd45ac2..a1ce638a 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetPatrolState.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetPatrolState.java
@@ -12,7 +12,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessagePatrolLeaderSetPatrolState implements BannerModMessage {
@@ -33,7 +32,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
dispatchToServer(player, this.recruit, this.state);
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetPatrollingSpeed.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetPatrollingSpeed.java
index 25b6fb79..4ca2896d 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetPatrollingSpeed.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetPatrollingSpeed.java
@@ -9,7 +9,6 @@
import net.minecraft.world.entity.Entity;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessagePatrolLeaderSetPatrollingSpeed implements BannerModMessage {
@@ -30,7 +29,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
Entity entity = player.serverLevel().getEntity(this.recruit);
if (entity instanceof AbstractLeaderEntity leader
&& RecruitCommandAuthority.canDirectlyControl(player, leader)
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetRoute.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetRoute.java
index a3f7799e..82daeab0 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetRoute.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetRoute.java
@@ -14,7 +14,6 @@
import javax.annotation.Nullable;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
/**
@@ -56,7 +55,8 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
dispatchToServer(player, this.recruit, this.routeId, this.waypoints, this.waitSeconds);
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetWaitTime.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetWaitTime.java
index 9fbdb948..f71a69f9 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetWaitTime.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePatrolLeaderSetWaitTime.java
@@ -9,7 +9,6 @@
import net.minecraft.world.entity.Entity;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessagePatrolLeaderSetWaitTime implements BannerModMessage {
@@ -31,7 +30,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
Entity entity = player.serverLevel().getEntity(this.recruit);
if (entity instanceof AbstractLeaderEntity leader
&& RecruitCommandAuthority.canDirectlyControl(player, leader)
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePromoteRecruit.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePromoteRecruit.java
index 62f55f07..6f749daf 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePromoteRecruit.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessagePromoteRecruit.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod.network.messages.military;
import com.talhanation.bannermod.army.command.RecruitCommandAuthority;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.network.payload.BannerModMessage;
import net.minecraft.network.protocol.PacketFlow;
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageProtectEntity.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageProtectEntity.java
index a1acd259..b3b079f3 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageProtectEntity.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageProtectEntity.java
@@ -11,7 +11,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageProtectEntity implements BannerModMessage {
@@ -37,7 +36,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context){
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
UUID actorUuid = authorizedPlayerUuid(player.getUUID(), this.uuid);
List recruits = this.group == null
? RecruitIndex.instance().ownerInRange(player.getCommandSenderWorld(), actorUuid, player.position(), 100.0D)
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRangedFire.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRangedFire.java
index a73a8ce0..975d46e0 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRangedFire.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRangedFire.java
@@ -12,7 +12,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageRangedFire implements BannerModMessage {
@@ -36,7 +35,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer sender = Objects.requireNonNull(context.getSender());
+ ServerPlayer sender = context.getSender();
+ if (sender == null) return;
dispatchToServer(sender, this.player, this.group, this.should);
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageReassignClaimPoliticalEntity.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageReassignClaimPoliticalEntity.java
index ebc15851..ebe4aca8 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageReassignClaimPoliticalEntity.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageReassignClaimPoliticalEntity.java
@@ -4,6 +4,7 @@
import com.talhanation.bannermod.config.RecruitsServerConfig;
import com.talhanation.bannermod.persistence.military.RecruitsClaim;
import com.talhanation.bannermod.war.WarRuntimeContext;
+import com.talhanation.bannermod.war.runtime.ClaimRepublisher;
import com.talhanation.bannermod.war.registry.PoliticalEntityAuthority;
import com.talhanation.bannermod.war.registry.PoliticalEntityRecord;
import com.talhanation.bannermod.war.registry.PoliticalRegistryRuntime;
@@ -79,38 +80,24 @@ public void executeServerSide(BannerModNetworkContext context) {
}
}
- UUID currentOwnerId = existingClaim.getOwnerPoliticalEntityId();
- if (java.util.Objects.equals(currentOwnerId, targetPoliticalEntityId)) {
- sendDenial(sender, "chat.bannermod.claim.transfer.denied.same");
- return;
- }
-
- // Source authority — must be able to edit the existing claim.
- if (!ClaimPacketAuthority.canEditClaim(sender.getUUID(), isAdmin, existingClaim, sourcePeRecord)) {
- sendDenial(sender, "chat.bannermod.claim.transfer.denied.no_source_authority");
- return;
- }
-
- // Target authority — only enforced when not admin and a target PE exists.
- // Detaching to no-state requires admin; non-admin callers must always pick
- // a target PE in which they hold authority.
- if (!isAdmin) {
- if (targetPeRecord == null) {
- sendDenial(sender, "chat.bannermod.claim.transfer.denied.no_target_authority");
- return;
- }
- if (!PoliticalEntityAuthority.canAct(sender.getUUID(), false, targetPeRecord)) {
- String reasonKey = PoliticalEntityAuthority.denialReasonKey(sender.getUUID(), false, targetPeRecord);
- sender.sendSystemMessage(Component.translatable("chat.bannermod.claim.transfer.denied.no_target_authority")
+ TransferResult transferResult = reassignClaimPoliticalEntityAndRepublish(
+ sender.getUUID(),
+ isAdmin,
+ existingClaim,
+ sourcePeRecord,
+ targetPeRecord,
+ targetPoliticalEntityId,
+ claim -> ClaimEvents.claimManager().addOrUpdateClaim(level, claim));
+ if (!transferResult.transferred()) {
+ if (transferResult.denialReasonKey() != null) {
+ sender.sendSystemMessage(Component.translatable(transferResult.denialKey())
.append(Component.literal(" "))
- .append(Component.translatable(reasonKey)));
- return;
+ .append(Component.translatable(transferResult.denialReasonKey())));
+ } else {
+ sendDenial(sender, transferResult.denialKey());
}
+ return;
}
-
- existingClaim.setOwnerPoliticalEntityId(targetPoliticalEntityId);
- ClaimEvents.claimManager().addOrUpdateClaim(level, existingClaim);
-
String targetName = targetPeRecord != null
? targetPeRecord.name()
: Component.translatable("chat.bannermod.claim.transfer.detached").getString();
@@ -125,6 +112,80 @@ private static void sendDenial(ServerPlayer sender, String key) {
sender.sendSystemMessage(Component.translatable(key));
}
+ static TransferResult reassignClaimPoliticalEntity(UUID actorUuid,
+ boolean admin,
+ RecruitsClaim existingClaim,
+ @Nullable PoliticalEntityRecord sourcePeRecord,
+ @Nullable PoliticalEntityRecord targetPeRecord,
+ @Nullable UUID targetPoliticalEntityId) {
+ if (existingClaim == null) {
+ return TransferResult.denied("chat.bannermod.claim.transfer.denied.missing");
+ }
+ if (targetPoliticalEntityId != null && targetPeRecord == null) {
+ return TransferResult.denied("chat.bannermod.claim.transfer.denied.target_missing");
+ }
+ UUID currentOwnerId = existingClaim.getOwnerPoliticalEntityId();
+ if (java.util.Objects.equals(currentOwnerId, targetPoliticalEntityId)) {
+ return TransferResult.denied("chat.bannermod.claim.transfer.denied.same");
+ }
+
+ // Source authority — must be able to edit the existing claim.
+ if (!ClaimPacketAuthority.canEditClaim(actorUuid, admin, existingClaim, sourcePeRecord)) {
+ return TransferResult.denied("chat.bannermod.claim.transfer.denied.no_source_authority");
+ }
+
+ // Target authority — only enforced when not admin and a target PE exists.
+ // Detaching to no-state requires admin; non-admin callers must always pick
+ // a target PE in which they hold authority.
+ if (!admin) {
+ if (targetPeRecord == null) {
+ return TransferResult.denied("chat.bannermod.claim.transfer.denied.no_target_authority");
+ }
+ if (!PoliticalEntityAuthority.canAct(actorUuid, false, targetPeRecord)) {
+ return TransferResult.denied(
+ "chat.bannermod.claim.transfer.denied.no_target_authority",
+ PoliticalEntityAuthority.denialReasonKey(actorUuid, false, targetPeRecord));
+ }
+ }
+
+ existingClaim.setOwnerPoliticalEntityId(targetPoliticalEntityId);
+ return TransferResult.success();
+ }
+
+ static TransferResult reassignClaimPoliticalEntityAndRepublish(UUID actorUuid,
+ boolean admin,
+ RecruitsClaim existingClaim,
+ @Nullable PoliticalEntityRecord sourcePeRecord,
+ @Nullable PoliticalEntityRecord targetPeRecord,
+ @Nullable UUID targetPoliticalEntityId,
+ ClaimRepublisher republisher) {
+ TransferResult result = reassignClaimPoliticalEntity(
+ actorUuid,
+ admin,
+ existingClaim,
+ sourcePeRecord,
+ targetPeRecord,
+ targetPoliticalEntityId);
+ if (result.transferred()) {
+ republisher.republish(existingClaim);
+ }
+ return result;
+ }
+
+ record TransferResult(boolean transferred, @Nullable String denialKey, @Nullable String denialReasonKey) {
+ static TransferResult success() {
+ return new TransferResult(true, null, null);
+ }
+
+ static TransferResult denied(String denialKey) {
+ return denied(denialKey, null);
+ }
+
+ static TransferResult denied(String denialKey, @Nullable String denialReasonKey) {
+ return new TransferResult(false, denialKey, denialReasonKey);
+ }
+ }
+
public MessageReassignClaimPoliticalEntity fromBytes(FriendlyByteBuf buf) {
this.claimUuid = buf.readUUID();
if (buf.readBoolean()) {
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRecruitGui.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRecruitGui.java
index 22d1c451..cee67df3 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRecruitGui.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRecruitGui.java
@@ -8,7 +8,6 @@
import net.minecraft.world.entity.player.Player;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageRecruitGui implements BannerModMessage {
@@ -34,7 +33,8 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
if (!player.getUUID().equals(uuid)) {
return;
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRemoveAssignedGroupFromCompanion.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRemoveAssignedGroupFromCompanion.java
index fee3b848..bf1ca799 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRemoveAssignedGroupFromCompanion.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRemoveAssignedGroupFromCompanion.java
@@ -2,7 +2,7 @@
import com.talhanation.bannermod.bootstrap.BannerModMain;
import com.talhanation.bannermod.army.command.RecruitCommandAuthority;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractLeaderEntity;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.entity.military.ICompanion;
@@ -38,6 +38,7 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
ServerPlayer serverPlayer = context.getSender();
+ if (serverPlayer == null) return;
Entity entity = serverPlayer.serverLevel().getEntity(this.companion);
if (entity instanceof AbstractLeaderEntity companionEntity
&& serverPlayer.getBoundingBox().inflate(100D).intersects(companionEntity.getBoundingBox())
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRest.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRest.java
index 9502dd9a..51ca0938 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRest.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageRest.java
@@ -9,7 +9,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageRest implements BannerModMessage {
@@ -33,7 +32,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer serverPlayer = Objects.requireNonNull(context.getSender());
+ ServerPlayer serverPlayer = context.getSender();
+ if (serverPlayer == null) return;
dispatchToServer(serverPlayer, this.player, this.group, this.should);
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageScoutTask.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageScoutTask.java
index c877c87f..54318305 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageScoutTask.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageScoutTask.java
@@ -6,12 +6,12 @@
import net.minecraft.network.protocol.PacketFlow;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageScoutTask implements BannerModMessage {
@@ -32,7 +32,10 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context){
context.enqueueWork(() -> {
- dispatchToServer(Objects.requireNonNull(context.getSender()), this.recruit, this.state);
+ ServerPlayer sender = context.getSender();
+ if (sender == null) return;
+
+ dispatchToServer(sender, this.recruit, this.state);
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSelectRecruits.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSelectRecruits.java
index dc2e129e..7303bafe 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSelectRecruits.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSelectRecruits.java
@@ -10,7 +10,6 @@
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
-import java.util.Objects;
import java.util.Set;
import java.util.UUID;
@@ -42,7 +41,8 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
Set set = new LinkedHashSet<>(this.recruitUuids);
if (this.clearFirst || set.isEmpty()) {
RecruitSelectionService.selectExplicit(player, set, SELECTION_RADIUS);
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSendMessenger.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSendMessenger.java
index 793fdadf..b09630e1 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSendMessenger.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSendMessenger.java
@@ -10,7 +10,6 @@
import net.minecraft.world.entity.Entity;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageSendMessenger implements BannerModMessage {
@@ -43,7 +42,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
Entity entity = player.serverLevel().getEntity(this.recruit);
if (entity instanceof MessengerEntity messenger
&& player.getBoundingBox().inflate(16D).intersects(messenger.getBoundingBox())) {
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSetLeaderGroup.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSetLeaderGroup.java
index fec646c9..e294f544 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSetLeaderGroup.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSetLeaderGroup.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod.network.messages.military;
import com.talhanation.bannermod.army.command.RecruitCommandAuthority;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractLeaderEntity;
import com.talhanation.bannermod.persistence.military.RecruitsGroup;
import com.talhanation.bannermod.network.payload.BannerModMessage;
@@ -12,7 +12,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import javax.annotation.Nullable;
-import java.util.Objects;
import java.util.UUID;
/**
@@ -40,7 +39,8 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
Entity entity = player.serverLevel().getEntity(this.leaderUUID);
if (!(entity instanceof AbstractLeaderEntity leader)
|| !leader.isAlive()
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageShields.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageShields.java
index 31cc253a..337c3e81 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageShields.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageShields.java
@@ -14,7 +14,6 @@
import java.util.HashSet;
import java.util.List;
-import java.util.Objects;
import java.util.Set;
import java.util.UUID;
@@ -39,7 +38,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
dispatchToServer(player, this.player, this.group, this.should);
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSplitGroup.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSplitGroup.java
index 3b96ed05..c7cd3de6 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSplitGroup.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageSplitGroup.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.network.messages.military;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.persistence.military.RecruitsGroup;
import com.talhanation.bannermod.network.payload.BannerModMessage;
import net.minecraft.network.protocol.PacketFlow;
@@ -8,7 +8,6 @@
import net.minecraft.server.level.ServerPlayer;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageSplitGroup implements BannerModMessage {
@@ -28,7 +27,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
RecruitsGroup groupToSplit = RecruitEvents.groupsManager().getGroup(groupUUID);
if(groupToSplit == null) return;
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageStrategicFire.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageStrategicFire.java
index 9e70660c..67b81fb9 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageStrategicFire.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageStrategicFire.java
@@ -14,7 +14,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageStrategicFire implements BannerModMessage {
@@ -38,7 +37,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer serverPlayer = Objects.requireNonNull(context.getSender());
+ ServerPlayer serverPlayer = context.getSender();
+ if (serverPlayer == null) return;
AABB commandBox = serverPlayer.getBoundingBox().inflate(100);
List actors = RecruitIndex.instance().groupInRange(
serverPlayer.getCommandSenderWorld(),
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageToClientUpdateGovernorScreen.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageToClientUpdateGovernorScreen.java
index 2f983492..072ed96d 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageToClientUpdateGovernorScreen.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageToClientUpdateGovernorScreen.java
@@ -8,7 +8,7 @@
import com.talhanation.bannermod.shared.settlement.BannerModSettlementClientSnapshotContract.RefreshTrigger;
import com.talhanation.bannermod.shared.settlement.BannerModSettlementClientSnapshotContract.SnapshotState;
import com.talhanation.bannermod.governance.BannerModGovernorSnapshot;
-import com.talhanation.bannermod.settlement.BannerModSettlementSnapshot;
+import com.talhanation.bannermod.settlement.SettlementSnapshot;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.PacketFlow;
@@ -57,10 +57,10 @@ public MessageToClientUpdateGovernorScreen fromBytes(FriendlyByteBuf buf) {
Payload payload = null;
if (buf.readBoolean()) {
UUID claimUuid = buf.readUUID();
- BannerModSettlementSnapshot settlementSnapshot = null;
+ SettlementSnapshot settlementSnapshot = null;
if (buf.readBoolean()) {
CompoundTag tag = buf.readNbt();
- settlementSnapshot = tag == null ? null : BannerModSettlementSnapshot.fromTag(tag);
+ settlementSnapshot = tag == null ? null : SettlementSnapshot.fromTag(tag);
}
BannerModGovernorSnapshot governorSnapshot = null;
if (buf.readBoolean()) {
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageTransferRoute.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageTransferRoute.java
index 10d5892e..1aa26b6a 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageTransferRoute.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageTransferRoute.java
@@ -9,7 +9,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import com.talhanation.bannermod.network.compat.BannerModPacketDistributor;
-import java.util.Objects;
import java.util.UUID;
import static com.talhanation.bannermod.bootstrap.BannerModMain.SIMPLE_CHANNEL;
@@ -38,7 +37,8 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer sender = Objects.requireNonNull(context.getSender());
+ ServerPlayer sender = context.getSender();
+ if (sender == null) return;
if (!isRouteTransferPayloadValid(targetPlayerUUID, routeNBT)) return;
ServerPlayer target = sender.getServer().getPlayerList().getPlayer(targetPlayerUUID);
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpdateGovernorPolicy.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpdateGovernorPolicy.java
index 57336be6..46e11006 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpdateGovernorPolicy.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpdateGovernorPolicy.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.network.messages.military;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.entity.military.AbstractRecruitEntity;
import com.talhanation.bannermod.governance.BannerModGovernorPolicy;
import com.talhanation.bannermod.network.payload.BannerModMessage;
@@ -9,7 +9,6 @@
import net.minecraft.server.level.ServerPlayer;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageUpdateGovernorPolicy implements BannerModMessage {
@@ -34,7 +33,8 @@ public PacketFlow getExecutingSide() {
@Override
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
BannerModGovernorPolicy[] policies = BannerModGovernorPolicy.values();
if (this.policyOrdinal < 0 || this.policyOrdinal >= policies.length) {
return;
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpdateGroup.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpdateGroup.java
index 81abe23e..0f36ecda 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpdateGroup.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpdateGroup.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod.network.messages.military;
import com.talhanation.bannermod.events.CommandEvents;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.persistence.military.RecruitsGroup;
import com.talhanation.bannermod.persistence.military.RecruitsGroupsManager;
import com.talhanation.bannermod.network.payload.BannerModMessage;
@@ -31,9 +31,10 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context){
context.enqueueWork(() -> {
- RecruitsGroup updatedGroup = RecruitsGroup.fromNBT(this.groupNBT);
ServerPlayer serverPLayer = context.getSender();
+ if (serverPLayer == null || this.groupNBT == null) return;
+ RecruitsGroup updatedGroup = RecruitsGroup.fromNBT(this.groupNBT);
RecruitEvents.groupsManager().addOrUpdateGroup((ServerLevel) serverPLayer.getCommandSenderWorld(), serverPLayer, updatedGroup);
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpkeepEntity.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpkeepEntity.java
index b0641b6a..d464cf22 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpkeepEntity.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpkeepEntity.java
@@ -12,7 +12,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageUpkeepEntity implements BannerModMessage {
@@ -36,7 +35,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
UUID actorUuid = authorizedPlayerUuid(player.getUUID(), this.player_uuid);
List recruits = this.group == null
? RecruitIndex.instance().ownerInRange(player.getCommandSenderWorld(), actorUuid, player.position(), 100.0D)
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpkeepPos.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpkeepPos.java
index 4bc13cdc..af621500 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpkeepPos.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageUpkeepPos.java
@@ -12,7 +12,6 @@
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
import java.util.List;
-import java.util.Objects;
import java.util.UUID;
public class MessageUpkeepPos implements BannerModMessage {
@@ -36,7 +35,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
dispatchToServer(player, this.player, this.group, this.pos);
});
}
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageWriteSpawnEgg.java b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageWriteSpawnEgg.java
index 030d1afa..73031ba4 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/military/MessageWriteSpawnEgg.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/military/MessageWriteSpawnEgg.java
@@ -15,7 +15,6 @@
import net.minecraft.world.item.component.CustomData;
import com.talhanation.bannermod.network.compat.BannerModNetworkContext;
-import java.util.Objects;
import java.util.UUID;
public class MessageWriteSpawnEgg implements BannerModMessage {
@@ -35,7 +34,8 @@ public PacketFlow getExecutingSide() {
public void executeServerSide(BannerModNetworkContext context) {
context.enqueueWork(() -> {
- ServerPlayer player = Objects.requireNonNull(context.getSender());
+ ServerPlayer player = context.getSender();
+ if (player == null) return;
Entity entity = player.serverLevel().getEntity(this.recruit);
if (entity instanceof CitizenEntity citizenEntity && citizenEntity.distanceToSqr(player) <= 64.0D * 64.0D) {
writeCitizenSpawnEggToHand(player, citizenEntity, InteractionHand.MAIN_HAND);
diff --git a/src/main/java/com/talhanation/bannermod/network/messages/war/MessageSetPoliticalEntityStatus.java b/src/main/java/com/talhanation/bannermod/network/messages/war/MessageSetPoliticalEntityStatus.java
index 733c9b07..571597de 100644
--- a/src/main/java/com/talhanation/bannermod/network/messages/war/MessageSetPoliticalEntityStatus.java
+++ b/src/main/java/com/talhanation/bannermod/network/messages/war/MessageSetPoliticalEntityStatus.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.network.messages.war;
-import com.talhanation.bannermod.settlement.BannerModSettlementManager;
+import com.talhanation.bannermod.settlement.SettlementManager;
import com.talhanation.bannermod.war.WarRuntimeContext;
import com.talhanation.bannermod.war.registry.PoliticalEntityAuthority;
import com.talhanation.bannermod.war.registry.PoliticalEntityRecord;
@@ -57,7 +57,7 @@ public void executeServerSide(BannerModNetworkContext context) {
PoliticalEntityStatus status = decodeStatus(this.statusOrdinal);
if (status == PoliticalEntityStatus.STATE && record.status() != PoliticalEntityStatus.STATE) {
PoliticalStatePromotionPolicy.Result promotion = PoliticalStatePromotionPolicy.evaluate(
- BannerModSettlementManager.get(level).getAllSnapshots().stream()
+ SettlementManager.get(level).getAllSnapshots().stream()
.filter(snapshot -> record.id().toString().equals(snapshot.settlementFactionId()))
.findFirst()
.orElse(null));
diff --git a/src/main/java/com/talhanation/bannermod/persistence/military/ClaimRemovalFanout.java b/src/main/java/com/talhanation/bannermod/persistence/military/ClaimRemovalFanout.java
index d0b0fa4a..7f03f25a 100644
--- a/src/main/java/com/talhanation/bannermod/persistence/military/ClaimRemovalFanout.java
+++ b/src/main/java/com/talhanation/bannermod/persistence/military/ClaimRemovalFanout.java
@@ -4,7 +4,7 @@
import com.talhanation.bannermod.entity.civilian.workarea.AbstractWorkAreaEntity;
import com.talhanation.bannermod.governance.BannerModGovernorManager;
import com.talhanation.bannermod.governance.BannerModTreasuryManager;
-import com.talhanation.bannermod.settlement.BannerModSettlementManager;
+import com.talhanation.bannermod.settlement.SettlementManager;
import com.talhanation.bannermod.war.WarRuntimeContext;
import com.talhanation.bannermod.war.runtime.OccupationRuntime;
import com.talhanation.bannermod.war.runtime.RevoltRuntime;
@@ -54,7 +54,7 @@ public static FanoutResult onClaimRemoved(@Nullable ServerLevel level,
return FanoutResult.empty();
}
BannerModTreasuryManager treasury = BannerModTreasuryManager.get(level);
- BannerModSettlementManager settlements = BannerModSettlementManager.get(level);
+ SettlementManager settlements = SettlementManager.get(level);
BannerModGovernorManager governors = BannerModGovernorManager.get(level);
OccupationRuntime occupations = WarRuntimeContext.occupations(level);
RevoltRuntime revolts = WarRuntimeContext.revolts(level);
@@ -71,7 +71,7 @@ public static FanoutResult onClaimRemoved(@Nullable ServerLevel level,
public static FanoutResult apply(@Nullable UUID claimUuid,
@Nullable List claimChunks,
@Nullable BannerModTreasuryManager treasury,
- @Nullable BannerModSettlementManager settlements,
+ @Nullable SettlementManager settlements,
@Nullable BannerModGovernorManager governors,
@Nullable OccupationRuntime occupations,
@Nullable RevoltRuntime revolts,
@@ -87,7 +87,7 @@ public static FanoutResult apply(@Nullable UUID claimUuid,
List removedRevolts = List.of();
// Detach worker bindings FIRST. The unbind path triggers a settlement-snapshot
- // refresh through BannerModSettlementService, which would otherwise re-seed the
+ // refresh through SettlementService, which would otherwise re-seed the
// snapshot we are about to drop. Doing this before the snapshot/treasury wipes
// keeps every removal visible in the same tick.
if (workers != null && claimChunks != null && !claimChunks.isEmpty()) {
diff --git a/src/main/java/com/talhanation/bannermod/persistence/military/RecruitsClaimManager.java b/src/main/java/com/talhanation/bannermod/persistence/military/RecruitsClaimManager.java
index 86417714..a7f918b6 100644
--- a/src/main/java/com/talhanation/bannermod/persistence/military/RecruitsClaimManager.java
+++ b/src/main/java/com/talhanation/bannermod/persistence/military/RecruitsClaimManager.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.persistence.military;
-import com.talhanation.bannermod.events.ClaimEvent;
+import com.talhanation.bannermod.api.event.ClaimEvent;
import net.neoforged.neoforge.common.NeoForge;
import com.talhanation.bannermod.bootstrap.BannerModMain;
diff --git a/src/main/java/com/talhanation/bannermod/persistence/military/RecruitsPatrolSpawn.java b/src/main/java/com/talhanation/bannermod/persistence/military/RecruitsPatrolSpawn.java
index c01c93b9..1283d09d 100644
--- a/src/main/java/com/talhanation/bannermod/persistence/military/RecruitsPatrolSpawn.java
+++ b/src/main/java/com/talhanation/bannermod/persistence/military/RecruitsPatrolSpawn.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.persistence.military;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.config.RecruitsServerConfig;
import com.talhanation.bannermod.entity.military.*;
import com.talhanation.bannermod.ai.military.villager.FollowCaravanOwner;
diff --git a/src/main/java/com/talhanation/bannermod/persistence/military/RecruitsPlayerUnitManager.java b/src/main/java/com/talhanation/bannermod/persistence/military/RecruitsPlayerUnitManager.java
index ed7821fd..f68d7a2b 100644
--- a/src/main/java/com/talhanation/bannermod/persistence/military/RecruitsPlayerUnitManager.java
+++ b/src/main/java/com/talhanation/bannermod/persistence/military/RecruitsPlayerUnitManager.java
@@ -1,7 +1,7 @@
package com.talhanation.bannermod.persistence.military;
import com.talhanation.bannermod.bootstrap.BannerModMain;
-import com.talhanation.bannermod.events.RecruitEvents;
+import com.talhanation.bannermod.entity.military.runtime.RecruitEvents;
import com.talhanation.bannermod.config.RecruitsServerConfig;
import com.talhanation.bannermod.network.messages.military.MessageToClientUpdateUnitInfo;
import net.minecraft.server.level.ServerLevel;
diff --git a/src/main/java/com/talhanation/bannermod/registry/ModAttachments.java b/src/main/java/com/talhanation/bannermod/registry/ModAttachments.java
new file mode 100644
index 00000000..197f49c1
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/registry/ModAttachments.java
@@ -0,0 +1,21 @@
+package com.talhanation.bannermod.registry;
+
+import com.talhanation.bannermod.bootstrap.BannerModMain;
+import com.talhanation.bannermod.entity.military.perks.PerkProgress;
+import net.neoforged.neoforge.attachment.AttachmentType;
+import net.neoforged.neoforge.registries.DeferredHolder;
+import net.neoforged.neoforge.registries.DeferredRegister;
+import net.neoforged.neoforge.registries.NeoForgeRegistries;
+
+public final class ModAttachments {
+ public static final DeferredRegister> ATTACHMENT_TYPES =
+ DeferredRegister.create(NeoForgeRegistries.ATTACHMENT_TYPES, BannerModMain.MOD_ID);
+
+ public static final DeferredHolder, AttachmentType> PLAYER_PERKS =
+ ATTACHMENT_TYPES.register("player_perks", () -> AttachmentType.serializable(PerkProgress::new)
+ .copyOnDeath()
+ .build());
+
+ private ModAttachments() {
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementDesiredGoodsSeed.java b/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementDesiredGoodsSeed.java
deleted file mode 100644
index b007e2ab..00000000
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementDesiredGoodsSeed.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.talhanation.bannermod.settlement;
-
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.nbt.ListTag;
-import net.minecraft.nbt.Tag;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public record BannerModSettlementDesiredGoodsSeed(
- List desiredGoods
-) {
- public BannerModSettlementDesiredGoodsSeed {
- desiredGoods = List.copyOf(desiredGoods == null ? List.of() : desiredGoods);
- }
-
- public CompoundTag toTag() {
- CompoundTag tag = new CompoundTag();
- ListTag desiredGoodsList = new ListTag();
- for (BannerModSettlementDesiredGoodSeed desiredGood : this.desiredGoods) {
- desiredGoodsList.add(desiredGood.toTag());
- }
- tag.put("DesiredGoods", desiredGoodsList);
- return tag;
- }
-
- public static BannerModSettlementDesiredGoodsSeed fromTag(CompoundTag tag) {
- List desiredGoods = new ArrayList<>();
- for (Tag entry : tag.getList("DesiredGoods", Tag.TAG_COMPOUND)) {
- desiredGoods.add(BannerModSettlementDesiredGoodSeed.fromTag((CompoundTag) entry));
- }
- return new BannerModSettlementDesiredGoodsSeed(desiredGoods);
- }
-
- public static BannerModSettlementDesiredGoodsSeed empty() {
- return new BannerModSettlementDesiredGoodsSeed(List.of());
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentJobDefinition.java b/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentJobDefinition.java
deleted file mode 100644
index 347a39db..00000000
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentJobDefinition.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.talhanation.bannermod.settlement;
-
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.nbt.Tag;
-
-import javax.annotation.Nullable;
-import java.util.UUID;
-
-public record BannerModSettlementResidentJobDefinition(
- BannerModSettlementJobHandlerSeed handlerSeed,
- @Nullable UUID targetBuildingUuid,
- @Nullable String targetBuildingTypeId,
- @Nullable BannerModSettlementBuildingCategory targetBuildingCategory,
- @Nullable BannerModSettlementBuildingProfileSeed targetBuildingProfileSeed
-) {
- public CompoundTag toTag() {
- CompoundTag tag = new CompoundTag();
- tag.putString("HandlerSeed", this.handlerSeed.name());
- if (this.targetBuildingUuid != null) {
- tag.putUUID("TargetBuildingUuid", this.targetBuildingUuid);
- }
- if (this.targetBuildingTypeId != null && !this.targetBuildingTypeId.isBlank()) {
- tag.putString("TargetBuildingTypeId", this.targetBuildingTypeId);
- }
- if (this.targetBuildingCategory != null) {
- tag.putString("TargetBuildingCategory", this.targetBuildingCategory.name());
- }
- if (this.targetBuildingProfileSeed != null) {
- tag.putString("TargetBuildingProfileSeed", this.targetBuildingProfileSeed.name());
- }
- return tag;
- }
-
- public static BannerModSettlementResidentJobDefinition fromTag(CompoundTag tag) {
- BannerModSettlementJobHandlerSeed handlerSeed = tag.contains("HandlerSeed", Tag.TAG_STRING)
- ? BannerModSettlementJobHandlerSeed.fromTagName(tag.getString("HandlerSeed"))
- : BannerModSettlementJobHandlerSeed.NONE;
- UUID targetBuildingUuid = tag.hasUUID("TargetBuildingUuid") ? tag.getUUID("TargetBuildingUuid") : null;
- String targetBuildingTypeId = tag.contains("TargetBuildingTypeId", Tag.TAG_STRING)
- ? tag.getString("TargetBuildingTypeId")
- : null;
- BannerModSettlementBuildingCategory targetBuildingCategory = tag.contains("TargetBuildingCategory", Tag.TAG_STRING)
- ? BannerModSettlementBuildingCategory.fromTagName(tag.getString("TargetBuildingCategory"))
- : null;
- BannerModSettlementBuildingProfileSeed targetBuildingProfileSeed = tag.contains("TargetBuildingProfileSeed", Tag.TAG_STRING)
- ? BannerModSettlementBuildingProfileSeed.fromTagName(tag.getString("TargetBuildingProfileSeed"))
- : null;
- return new BannerModSettlementResidentJobDefinition(handlerSeed, targetBuildingUuid, targetBuildingTypeId, targetBuildingCategory, targetBuildingProfileSeed);
- }
-
- public static BannerModSettlementResidentJobDefinition defaultFor(BannerModSettlementResidentRole role,
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed,
- BannerModSettlementResidentServiceContract serviceContract,
- @Nullable BannerModSettlementBuildingRecord building) {
- return switch (runtimeRoleSeed) {
- case VILLAGE_LIFE -> new BannerModSettlementResidentJobDefinition(BannerModSettlementJobHandlerSeed.VILLAGE_LIFE, null, null, null, null);
- case GOVERNANCE -> new BannerModSettlementResidentJobDefinition(BannerModSettlementJobHandlerSeed.GOVERNANCE, null, null, null, null);
- case LOCAL_LABOR -> new BannerModSettlementResidentJobDefinition(
- resolveLocalLaborHandler(role, serviceContract),
- serviceContract.serviceBuildingUuid(),
- resolveBuildingTypeId(serviceContract, building),
- building == null ? null : building.buildingCategory(),
- building == null ? null : building.buildingProfileSeed()
- );
- case FLOATING_LABOR -> new BannerModSettlementResidentJobDefinition(BannerModSettlementJobHandlerSeed.FLOATING_LABOR_POOL, null, null, null, null);
- case ORPHANED_LABOR_ASSIGNMENT -> new BannerModSettlementResidentJobDefinition(
- BannerModSettlementJobHandlerSeed.ORPHANED_LABOR_RECOVERY,
- serviceContract.serviceBuildingUuid(),
- serviceContract.serviceBuildingTypeId(),
- null,
- null
- );
- };
- }
-
- private static BannerModSettlementJobHandlerSeed resolveLocalLaborHandler(BannerModSettlementResidentRole role,
- BannerModSettlementResidentServiceContract serviceContract) {
- if (role == BannerModSettlementResidentRole.CONTROLLED_WORKER
- && serviceContract.actorState() == BannerModSettlementServiceActorState.LOCAL_BUILDING_SERVICE) {
- return BannerModSettlementJobHandlerSeed.LOCAL_BUILDING_LABOR;
- }
- return BannerModSettlementJobHandlerSeed.NONE;
- }
-
- private static String resolveBuildingTypeId(BannerModSettlementResidentServiceContract serviceContract,
- @Nullable BannerModSettlementBuildingRecord building) {
- if (building != null) {
- return building.buildingTypeId();
- }
- return serviceContract.serviceBuildingTypeId();
- }
-
- public static BannerModSettlementResidentJobDefinition none() {
- return new BannerModSettlementResidentJobDefinition(BannerModSettlementJobHandlerSeed.NONE, null, null, null, null);
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentJobTargetSelectionSeed.java b/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentJobTargetSelectionSeed.java
deleted file mode 100644
index 8e23f53d..00000000
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentJobTargetSelectionSeed.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.talhanation.bannermod.settlement;
-
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.nbt.Tag;
-
-import javax.annotation.Nullable;
-import java.util.UUID;
-
-public record BannerModSettlementResidentJobTargetSelectionSeed(
- BannerModSettlementJobTargetSelectionMode selectionMode,
- @Nullable UUID targetMarketUuid,
- @Nullable String targetMarketName
-) {
- public CompoundTag toTag() {
- CompoundTag tag = new CompoundTag();
- tag.putString("SelectionMode", this.selectionMode.name());
- if (this.targetMarketUuid != null) {
- tag.putUUID("TargetMarketUuid", this.targetMarketUuid);
- }
- if (this.targetMarketName != null && !this.targetMarketName.isBlank()) {
- tag.putString("TargetMarketName", this.targetMarketName);
- }
- return tag;
- }
-
- public static BannerModSettlementResidentJobTargetSelectionSeed fromTag(CompoundTag tag) {
- BannerModSettlementJobTargetSelectionMode selectionMode = tag.contains("SelectionMode", Tag.TAG_STRING)
- ? BannerModSettlementJobTargetSelectionMode.fromTagName(tag.getString("SelectionMode"))
- : BannerModSettlementJobTargetSelectionMode.NONE;
- UUID targetMarketUuid = tag.hasUUID("TargetMarketUuid") ? tag.getUUID("TargetMarketUuid") : null;
- String targetMarketName = tag.contains("TargetMarketName", Tag.TAG_STRING)
- ? tag.getString("TargetMarketName")
- : null;
- return new BannerModSettlementResidentJobTargetSelectionSeed(selectionMode, targetMarketUuid, targetMarketName);
- }
-
- public static BannerModSettlementResidentJobTargetSelectionSeed defaultFor(UUID residentUuid,
- BannerModSettlementResidentJobDefinition jobDefinition,
- BannerModSettlementResidentServiceContract serviceContract,
- BannerModSettlementMarketState marketState) {
- BannerModSettlementSellerDispatchRecord sellerDispatch = findSellerDispatch(residentUuid, marketState);
- if (sellerDispatch != null) {
- return new BannerModSettlementResidentJobTargetSelectionSeed(
- sellerDispatch.dispatchState() == BannerModSettlementSellerDispatchState.READY
- ? BannerModSettlementJobTargetSelectionMode.SELLER_MARKET_DISPATCH
- : BannerModSettlementJobTargetSelectionMode.SELLER_MARKET_CLOSED,
- sellerDispatch.marketUuid(),
- sellerDispatch.marketName()
- );
- }
-
- return switch (jobDefinition.handlerSeed()) {
- case LOCAL_BUILDING_LABOR -> serviceContract.actorState() == BannerModSettlementServiceActorState.LOCAL_BUILDING_SERVICE
- ? new BannerModSettlementResidentJobTargetSelectionSeed(BannerModSettlementJobTargetSelectionMode.SERVICE_BUILDING, null, null)
- : none();
- case FLOATING_LABOR_POOL -> new BannerModSettlementResidentJobTargetSelectionSeed(BannerModSettlementJobTargetSelectionMode.FLOATING_LABOR_POOL, null, null);
- case ORPHANED_LABOR_RECOVERY -> new BannerModSettlementResidentJobTargetSelectionSeed(BannerModSettlementJobTargetSelectionMode.ORPHANED_SERVICE_BUILDING, null, null);
- default -> none();
- };
- }
-
- public static BannerModSettlementResidentJobTargetSelectionSeed none() {
- return new BannerModSettlementResidentJobTargetSelectionSeed(BannerModSettlementJobTargetSelectionMode.NONE, null, null);
- }
-
- @Nullable
- private static BannerModSettlementSellerDispatchRecord findSellerDispatch(UUID residentUuid,
- BannerModSettlementMarketState marketState) {
- for (BannerModSettlementSellerDispatchRecord sellerDispatch : marketState.sellerDispatches()) {
- if (sellerDispatch.residentUuid().equals(residentUuid)) {
- return sellerDispatch;
- }
- }
- return null;
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentRecord.java b/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentRecord.java
deleted file mode 100644
index 6ea22702..00000000
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentRecord.java
+++ /dev/null
@@ -1,286 +0,0 @@
-package com.talhanation.bannermod.settlement;
-
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.nbt.Tag;
-
-import javax.annotation.Nullable;
-import java.util.UUID;
-
-public record BannerModSettlementResidentRecord(
- UUID residentUuid,
- BannerModSettlementResidentRole role,
- BannerModSettlementResidentScheduleSeed scheduleSeed,
- BannerModSettlementResidentScheduleWindowSeed scheduleWindowSeed,
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed,
- BannerModSettlementResidentServiceContract serviceContract,
- BannerModSettlementResidentJobDefinition jobDefinition,
- BannerModSettlementResidentJobTargetSelectionSeed jobTargetSelectionSeed,
- BannerModSettlementResidentMode residentMode,
- @Nullable UUID ownerUuid,
- @Nullable String teamId,
- @Nullable UUID boundWorkAreaUuid,
- BannerModSettlementResidentAssignmentState assignmentState,
- BannerModSettlementResidentRoleProfile roleProfile,
- BannerModSettlementResidentSchedulePolicy schedulePolicy
-) {
- public BannerModSettlementResidentRecord(UUID residentUuid,
- BannerModSettlementResidentRole role,
- BannerModSettlementResidentScheduleSeed scheduleSeed,
- BannerModSettlementResidentScheduleWindowSeed scheduleWindowSeed,
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed,
- BannerModSettlementResidentServiceContract serviceContract,
- BannerModSettlementResidentJobDefinition jobDefinition,
- BannerModSettlementResidentJobTargetSelectionSeed jobTargetSelectionSeed,
- BannerModSettlementResidentMode residentMode,
- @Nullable UUID ownerUuid,
- @Nullable String teamId,
- @Nullable UUID boundWorkAreaUuid,
- BannerModSettlementResidentAssignmentState assignmentState,
- BannerModSettlementResidentRoleProfile roleProfile) {
- this(
- residentUuid,
- role,
- scheduleSeed,
- scheduleWindowSeed,
- runtimeRoleSeed,
- serviceContract,
- jobDefinition,
- jobTargetSelectionSeed,
- residentMode,
- ownerUuid,
- teamId,
- boundWorkAreaUuid,
- assignmentState,
- roleProfile,
- BannerModSettlementResidentSchedulePolicy.defaultFor(scheduleSeed, scheduleWindowSeed, runtimeRoleSeed, roleProfile)
- );
- }
-
- public BannerModSettlementResidentRecord(UUID residentUuid,
- BannerModSettlementResidentRole role,
- BannerModSettlementResidentScheduleSeed scheduleSeed,
- BannerModSettlementResidentScheduleWindowSeed scheduleWindowSeed,
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed,
- BannerModSettlementResidentServiceContract serviceContract,
- BannerModSettlementResidentJobDefinition jobDefinition,
- BannerModSettlementResidentJobTargetSelectionSeed jobTargetSelectionSeed,
- BannerModSettlementResidentMode residentMode,
- @Nullable UUID ownerUuid,
- @Nullable String teamId,
- @Nullable UUID boundWorkAreaUuid,
- BannerModSettlementResidentAssignmentState assignmentState) {
- this(
- residentUuid,
- role,
- scheduleSeed,
- scheduleWindowSeed,
- runtimeRoleSeed,
- serviceContract,
- jobDefinition,
- jobTargetSelectionSeed,
- residentMode,
- ownerUuid,
- teamId,
- boundWorkAreaUuid,
- assignmentState,
- BannerModSettlementResidentRoleProfile.defaultFor(role, runtimeRoleSeed, residentMode, assignmentState)
- );
- }
-
- public BannerModSettlementResidentRecord(UUID residentUuid,
- BannerModSettlementResidentRole role,
- BannerModSettlementResidentScheduleSeed scheduleSeed,
- BannerModSettlementResidentScheduleWindowSeed scheduleWindowSeed,
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed,
- BannerModSettlementResidentServiceContract serviceContract,
- BannerModSettlementResidentJobDefinition jobDefinition,
- BannerModSettlementResidentMode residentMode,
- @Nullable UUID ownerUuid,
- @Nullable String teamId,
- @Nullable UUID boundWorkAreaUuid,
- BannerModSettlementResidentAssignmentState assignmentState) {
- this(
- residentUuid,
- role,
- scheduleSeed,
- scheduleWindowSeed,
- runtimeRoleSeed,
- serviceContract,
- jobDefinition,
- BannerModSettlementResidentJobTargetSelectionSeed.defaultFor(residentUuid, jobDefinition, serviceContract, BannerModSettlementMarketState.empty()),
- residentMode,
- ownerUuid,
- teamId,
- boundWorkAreaUuid,
- assignmentState,
- BannerModSettlementResidentRoleProfile.defaultFor(role, runtimeRoleSeed, residentMode, assignmentState)
- );
- }
-
- public BannerModSettlementResidentRecord(UUID residentUuid,
- BannerModSettlementResidentRole role,
- BannerModSettlementResidentScheduleSeed scheduleSeed,
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed,
- BannerModSettlementResidentServiceContract serviceContract,
- BannerModSettlementResidentMode residentMode,
- @Nullable UUID ownerUuid,
- @Nullable String teamId,
- @Nullable UUID boundWorkAreaUuid,
- BannerModSettlementResidentAssignmentState assignmentState) {
- this(
- residentUuid,
- role,
- scheduleSeed,
- BannerModSettlementResidentScheduleWindowSeed.defaultFor(scheduleSeed, runtimeRoleSeed),
- runtimeRoleSeed,
- serviceContract,
- BannerModSettlementResidentJobDefinition.defaultFor(role, runtimeRoleSeed, serviceContract, null),
- BannerModSettlementResidentJobTargetSelectionSeed.defaultFor(
- residentUuid,
- BannerModSettlementResidentJobDefinition.defaultFor(role, runtimeRoleSeed, serviceContract, null),
- serviceContract,
- BannerModSettlementMarketState.empty()
- ),
- residentMode,
- ownerUuid,
- teamId,
- boundWorkAreaUuid,
- assignmentState,
- BannerModSettlementResidentRoleProfile.defaultFor(role, runtimeRoleSeed, residentMode, assignmentState)
- );
- }
-
- public BannerModSettlementResidentRecord(UUID residentUuid,
- BannerModSettlementResidentRole role,
- BannerModSettlementResidentScheduleSeed scheduleSeed,
- BannerModSettlementResidentScheduleWindowSeed scheduleWindowSeed,
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed,
- BannerModSettlementResidentServiceContract serviceContract,
- BannerModSettlementResidentMode residentMode,
- @Nullable UUID ownerUuid,
- @Nullable String teamId,
- @Nullable UUID boundWorkAreaUuid,
- BannerModSettlementResidentAssignmentState assignmentState) {
- this(
- residentUuid,
- role,
- scheduleSeed,
- scheduleWindowSeed,
- runtimeRoleSeed,
- serviceContract,
- BannerModSettlementResidentJobDefinition.defaultFor(role, runtimeRoleSeed, serviceContract, null),
- BannerModSettlementResidentJobTargetSelectionSeed.defaultFor(
- residentUuid,
- BannerModSettlementResidentJobDefinition.defaultFor(role, runtimeRoleSeed, serviceContract, null),
- serviceContract,
- BannerModSettlementMarketState.empty()
- ),
- residentMode,
- ownerUuid,
- teamId,
- boundWorkAreaUuid,
- assignmentState,
- BannerModSettlementResidentRoleProfile.defaultFor(role, runtimeRoleSeed, residentMode, assignmentState)
- );
- }
-
- public CompoundTag toTag() {
- CompoundTag tag = new CompoundTag();
- tag.putUUID("ResidentUuid", this.residentUuid);
- tag.putString("Role", this.role.name());
- tag.putString("ScheduleSeed", this.scheduleSeed.name());
- tag.putString("ScheduleWindowSeed", this.scheduleWindowSeed.name());
- tag.putString("RuntimeRoleSeed", this.runtimeRoleSeed.name());
- tag.put("ServiceContract", this.serviceContract.toTag());
- tag.put("JobDefinition", this.jobDefinition.toTag());
- tag.put("JobTargetSelectionSeed", this.jobTargetSelectionSeed.toTag());
- tag.putString("ResidentMode", this.residentMode.name());
- if (this.ownerUuid != null) {
- tag.putUUID("OwnerUuid", this.ownerUuid);
- }
- if (this.teamId != null && !this.teamId.isBlank()) {
- tag.putString("TeamId", this.teamId);
- }
- if (this.boundWorkAreaUuid != null) {
- tag.putUUID("BoundWorkAreaUuid", this.boundWorkAreaUuid);
- }
- tag.putString("AssignmentState", this.assignmentState.name());
- tag.put("RoleProfile", this.roleProfile.toTag());
- tag.put("SchedulePolicy", this.schedulePolicy.toTag());
- return tag;
- }
-
- public static BannerModSettlementResidentRecord fromTag(CompoundTag tag) {
- BannerModSettlementResidentRole role = BannerModSettlementResidentRole.fromTagName(tag.getString("Role"));
- UUID ownerUuid = tag.hasUUID("OwnerUuid") ? tag.getUUID("OwnerUuid") : null;
- String teamId = tag.contains("TeamId", Tag.TAG_STRING) ? tag.getString("TeamId") : null;
- UUID boundWorkAreaUuid = tag.hasUUID("BoundWorkAreaUuid") ? tag.getUUID("BoundWorkAreaUuid") : null;
- BannerModSettlementResidentScheduleSeed scheduleSeed = tag.contains("ScheduleSeed", Tag.TAG_STRING)
- ? scheduleSeedFromTagName(tag.getString("ScheduleSeed"), role, boundWorkAreaUuid)
- : BannerModSettlementResidentScheduleSeed.defaultFor(role, boundWorkAreaUuid);
- BannerModSettlementResidentMode residentMode = tag.contains("ResidentMode", Tag.TAG_STRING)
- ? BannerModSettlementResidentMode.fromTagName(tag.getString("ResidentMode"))
- : BannerModSettlementResidentMode.defaultFor(role, ownerUuid);
- BannerModSettlementResidentAssignmentState assignmentState = tag.contains("AssignmentState", Tag.TAG_STRING)
- ? BannerModSettlementResidentAssignmentState.fromTagName(tag.getString("AssignmentState"))
- : defaultAssignmentState(role, boundWorkAreaUuid);
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed = tag.contains("RuntimeRoleSeed", Tag.TAG_STRING)
- ? BannerModSettlementResidentRuntimeRoleSeed.fromTagName(tag.getString("RuntimeRoleSeed"))
- : BannerModSettlementResidentRuntimeRoleSeed.defaultFor(role, scheduleSeed, residentMode, assignmentState);
- BannerModSettlementResidentScheduleWindowSeed scheduleWindowSeed = tag.contains("ScheduleWindowSeed", Tag.TAG_STRING)
- ? BannerModSettlementResidentScheduleWindowSeed.fromTagName(tag.getString("ScheduleWindowSeed"))
- : BannerModSettlementResidentScheduleWindowSeed.defaultFor(scheduleSeed, runtimeRoleSeed);
- BannerModSettlementResidentServiceContract serviceContract = tag.contains("ServiceContract", Tag.TAG_COMPOUND)
- ? BannerModSettlementResidentServiceContract.fromTag(tag.getCompound("ServiceContract"))
- : BannerModSettlementResidentServiceContract.defaultFor(role, residentMode, assignmentState, boundWorkAreaUuid, null);
- BannerModSettlementResidentJobDefinition jobDefinition = tag.contains("JobDefinition", Tag.TAG_COMPOUND)
- ? BannerModSettlementResidentJobDefinition.fromTag(tag.getCompound("JobDefinition"))
- : BannerModSettlementResidentJobDefinition.defaultFor(role, runtimeRoleSeed, serviceContract, null);
- BannerModSettlementResidentJobTargetSelectionSeed jobTargetSelectionSeed = tag.contains("JobTargetSelectionSeed", Tag.TAG_COMPOUND)
- ? BannerModSettlementResidentJobTargetSelectionSeed.fromTag(tag.getCompound("JobTargetSelectionSeed"))
- : BannerModSettlementResidentJobTargetSelectionSeed.defaultFor(tag.getUUID("ResidentUuid"), jobDefinition, serviceContract, BannerModSettlementMarketState.empty());
- BannerModSettlementResidentRoleProfile roleProfile = tag.contains("RoleProfile", Tag.TAG_COMPOUND)
- ? BannerModSettlementResidentRoleProfile.fromTag(tag.getCompound("RoleProfile"))
- : BannerModSettlementResidentRoleProfile.defaultFor(role, runtimeRoleSeed, residentMode, assignmentState);
- BannerModSettlementResidentSchedulePolicy schedulePolicy = tag.contains("SchedulePolicy", Tag.TAG_COMPOUND)
- ? BannerModSettlementResidentSchedulePolicy.fromTag(tag.getCompound("SchedulePolicy"))
- : BannerModSettlementResidentSchedulePolicy.defaultFor(scheduleSeed, scheduleWindowSeed, runtimeRoleSeed, roleProfile);
- return new BannerModSettlementResidentRecord(
- tag.getUUID("ResidentUuid"),
- role,
- scheduleSeed,
- scheduleWindowSeed,
- runtimeRoleSeed,
- serviceContract,
- jobDefinition,
- jobTargetSelectionSeed,
- residentMode,
- ownerUuid,
- teamId,
- boundWorkAreaUuid,
- assignmentState,
- roleProfile,
- schedulePolicy
- );
- }
-
- private static BannerModSettlementResidentAssignmentState defaultAssignmentState(BannerModSettlementResidentRole role,
- @Nullable UUID boundWorkAreaUuid) {
- if (role != BannerModSettlementResidentRole.CONTROLLED_WORKER) {
- return BannerModSettlementResidentAssignmentState.NOT_APPLICABLE;
- }
- return boundWorkAreaUuid == null
- ? BannerModSettlementResidentAssignmentState.UNASSIGNED
- : BannerModSettlementResidentAssignmentState.ASSIGNED_LOCAL_BUILDING;
- }
-
- private static BannerModSettlementResidentScheduleSeed scheduleSeedFromTagName(String name,
- BannerModSettlementResidentRole role,
- @Nullable UUID boundWorkAreaUuid) {
- try {
- return BannerModSettlementResidentScheduleSeed.valueOf(name);
- } catch (IllegalArgumentException exception) {
- return BannerModSettlementResidentScheduleSeed.defaultFor(role, boundWorkAreaUuid);
- }
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentRuntimeRoleSeed.java b/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentRuntimeRoleSeed.java
deleted file mode 100644
index f3397a23..00000000
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentRuntimeRoleSeed.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.talhanation.bannermod.settlement;
-
-public enum BannerModSettlementResidentRuntimeRoleSeed {
- VILLAGE_LIFE,
- GOVERNANCE,
- LOCAL_LABOR,
- FLOATING_LABOR,
- ORPHANED_LABOR_ASSIGNMENT;
-
- public static BannerModSettlementResidentRuntimeRoleSeed fromTagName(String name) {
- if (name == null || name.isBlank()) {
- return VILLAGE_LIFE;
- }
- try {
- return valueOf(name);
- } catch (IllegalArgumentException ignored) {
- return VILLAGE_LIFE;
- }
- }
-
- public static BannerModSettlementResidentRuntimeRoleSeed defaultFor(BannerModSettlementResidentRole role,
- BannerModSettlementResidentScheduleSeed scheduleSeed,
- BannerModSettlementResidentMode residentMode,
- BannerModSettlementResidentAssignmentState assignmentState) {
- return switch (role) {
- case GOVERNOR_RECRUIT -> GOVERNANCE;
- case VILLAGER -> VILLAGE_LIFE;
- case CONTROLLED_WORKER -> defaultWorkerSeed(scheduleSeed, residentMode, assignmentState);
- };
- }
-
- private static BannerModSettlementResidentRuntimeRoleSeed defaultWorkerSeed(BannerModSettlementResidentScheduleSeed scheduleSeed,
- BannerModSettlementResidentMode residentMode,
- BannerModSettlementResidentAssignmentState assignmentState) {
- if (assignmentState == BannerModSettlementResidentAssignmentState.ASSIGNED_MISSING_BUILDING) {
- return ORPHANED_LABOR_ASSIGNMENT;
- }
- if (assignmentState == BannerModSettlementResidentAssignmentState.ASSIGNED_LOCAL_BUILDING
- || scheduleSeed == BannerModSettlementResidentScheduleSeed.ASSIGNED_WORK) {
- return LOCAL_LABOR;
- }
- if (residentMode == BannerModSettlementResidentMode.PROJECTED_CONTROLLED_WORKER) {
- return FLOATING_LABOR;
- }
- return FLOATING_LABOR;
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentSchedulePolicy.java b/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentSchedulePolicy.java
deleted file mode 100644
index bd0bdd26..00000000
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentSchedulePolicy.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.talhanation.bannermod.settlement;
-
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.nbt.Tag;
-
-public record BannerModSettlementResidentSchedulePolicy(
- BannerModSettlementResidentSchedulePolicySeed policySeed,
- BannerModSettlementResidentScheduleSeed scheduleSeed,
- BannerModSettlementResidentScheduleWindowSeed scheduleWindowSeed,
- String goalDomainId,
- boolean prefersLocalBuilding
-) {
- public CompoundTag toTag() {
- CompoundTag tag = new CompoundTag();
- tag.putString("PolicySeed", this.policySeed.name());
- tag.putString("ScheduleSeed", this.scheduleSeed.name());
- tag.putString("ScheduleWindowSeed", this.scheduleWindowSeed.name());
- tag.putString("GoalDomainId", this.goalDomainId);
- tag.putBoolean("PrefersLocalBuilding", this.prefersLocalBuilding);
- return tag;
- }
-
- public static BannerModSettlementResidentSchedulePolicy fromTag(CompoundTag tag) {
- BannerModSettlementResidentSchedulePolicySeed policySeed = tag.contains("PolicySeed", Tag.TAG_STRING)
- ? BannerModSettlementResidentSchedulePolicySeed.fromTagName(tag.getString("PolicySeed"))
- : BannerModSettlementResidentSchedulePolicySeed.VILLAGE_LIFE_FLEX;
- BannerModSettlementResidentScheduleSeed scheduleSeed = tag.contains("ScheduleSeed", Tag.TAG_STRING)
- ? scheduleSeedFromTagName(tag.getString("ScheduleSeed"))
- : BannerModSettlementResidentScheduleSeed.SETTLEMENT_IDLE;
- BannerModSettlementResidentScheduleWindowSeed scheduleWindowSeed = tag.contains("ScheduleWindowSeed", Tag.TAG_STRING)
- ? BannerModSettlementResidentScheduleWindowSeed.fromTagName(tag.getString("ScheduleWindowSeed"))
- : BannerModSettlementResidentScheduleWindowSeed.DAYLIGHT_FLEX;
- String goalDomainId = tag.contains("GoalDomainId", Tag.TAG_STRING)
- ? tag.getString("GoalDomainId")
- : "village";
- return new BannerModSettlementResidentSchedulePolicy(
- policySeed,
- scheduleSeed,
- scheduleWindowSeed,
- goalDomainId,
- tag.getBoolean("PrefersLocalBuilding")
- );
- }
-
- public static BannerModSettlementResidentSchedulePolicy defaultFor(BannerModSettlementResidentScheduleSeed scheduleSeed,
- BannerModSettlementResidentScheduleWindowSeed scheduleWindowSeed,
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed,
- BannerModSettlementResidentRoleProfile roleProfile) {
- return new BannerModSettlementResidentSchedulePolicy(
- defaultPolicySeed(scheduleSeed, scheduleWindowSeed, runtimeRoleSeed),
- scheduleSeed,
- scheduleWindowSeed,
- roleProfile.goalDomainId(),
- roleProfile.prefersLocalBuilding()
- );
- }
-
- private static BannerModSettlementResidentSchedulePolicySeed defaultPolicySeed(BannerModSettlementResidentScheduleSeed scheduleSeed,
- BannerModSettlementResidentScheduleWindowSeed scheduleWindowSeed,
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed) {
- return switch (runtimeRoleSeed) {
- case GOVERNANCE -> BannerModSettlementResidentSchedulePolicySeed.GOVERNANCE_CIVIC;
- case LOCAL_LABOR -> BannerModSettlementResidentSchedulePolicySeed.LOCAL_LABOR_DAY;
- case FLOATING_LABOR -> scheduleWindowSeed == BannerModSettlementResidentScheduleWindowSeed.LABOR_DAY
- || scheduleSeed == BannerModSettlementResidentScheduleSeed.ASSIGNED_WORK
- ? BannerModSettlementResidentSchedulePolicySeed.LOCAL_LABOR_DAY
- : BannerModSettlementResidentSchedulePolicySeed.FLOATING_LABOR_FLEX;
- case ORPHANED_LABOR_ASSIGNMENT -> BannerModSettlementResidentSchedulePolicySeed.ORPHANED_LABOR_DAY;
- case VILLAGE_LIFE -> scheduleWindowSeed == BannerModSettlementResidentScheduleWindowSeed.CIVIC_DAY
- || scheduleSeed == BannerModSettlementResidentScheduleSeed.GOVERNING
- ? BannerModSettlementResidentSchedulePolicySeed.GOVERNANCE_CIVIC
- : BannerModSettlementResidentSchedulePolicySeed.VILLAGE_LIFE_FLEX;
- };
- }
-
- private static BannerModSettlementResidentScheduleSeed scheduleSeedFromTagName(String name) {
- try {
- return BannerModSettlementResidentScheduleSeed.valueOf(name);
- } catch (IllegalArgumentException exception) {
- return BannerModSettlementResidentScheduleSeed.SETTLEMENT_IDLE;
- }
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentStaffingService.java b/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentStaffingService.java
deleted file mode 100644
index b47c1454..00000000
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentStaffingService.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.talhanation.bannermod.settlement;
-
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-
-final class BannerModSettlementResidentStaffingService {
-
- private BannerModSettlementResidentStaffingService() {
- }
-
- static StaffingResult apply(List residents,
- List buildings,
- BannerModSettlementMarketState marketState,
- Set localBuildingUuids) {
- List staffedResidents = BannerModSettlementService.applyResidentAssignmentSemantics(
- residents,
- localBuildingUuids
- );
- staffedResidents = BannerModSettlementService.applyResidentServiceContracts(staffedResidents, buildings);
- staffedResidents = BannerModSettlementService.applyResidentJobDefinitions(staffedResidents, buildings);
- List staffedBuildings = BannerModSettlementService.applyAssignedResidents(buildings, staffedResidents);
- BannerModSettlementMarketState staffedMarketState = BannerModSettlementService.applySellerDispatchSeed(
- marketState,
- staffedResidents,
- staffedBuildings
- );
- staffedResidents = BannerModSettlementService.applyResidentJobTargetSelectionSeeds(staffedResidents, staffedMarketState);
- return new StaffingResult(staffedResidents, staffedBuildings, staffedMarketState);
- }
-
- record StaffingResult(List residents,
- List buildings,
- BannerModSettlementMarketState marketState) {
- }
-}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementBuildingCategory.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementBuildingCategory.java
similarity index 61%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementBuildingCategory.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementBuildingCategory.java
index 868c6382..fe8d605f 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementBuildingCategory.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementBuildingCategory.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.settlement;
-public enum BannerModSettlementBuildingCategory {
+public enum SettlementBuildingCategory {
FOOD,
MATERIAL,
STORAGE,
@@ -8,12 +8,12 @@ public enum BannerModSettlementBuildingCategory {
CONSTRUCTION,
GENERAL;
- public static BannerModSettlementBuildingCategory fromTagName(String name) {
+ public static SettlementBuildingCategory fromTagName(String name) {
if (name == null || name.isBlank()) {
return GENERAL;
}
try {
- return BannerModSettlementBuildingCategory.valueOf(name);
+ return SettlementBuildingCategory.valueOf(name);
} catch (IllegalArgumentException exception) {
return GENERAL;
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementBuildingProfileSeed.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementBuildingProfileSeed.java
similarity index 68%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementBuildingProfileSeed.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementBuildingProfileSeed.java
index d125349d..1a736866 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementBuildingProfileSeed.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementBuildingProfileSeed.java
@@ -11,25 +11,25 @@
import com.talhanation.bannermod.entity.civilian.workarea.StorageArea;
import net.minecraft.resources.ResourceLocation;
-public enum BannerModSettlementBuildingProfileSeed {
- FOOD_PRODUCTION(BannerModSettlementBuildingCategory.FOOD),
- MATERIAL_PRODUCTION(BannerModSettlementBuildingCategory.MATERIAL),
- STORAGE(BannerModSettlementBuildingCategory.STORAGE),
- MARKET(BannerModSettlementBuildingCategory.MARKET),
- CONSTRUCTION(BannerModSettlementBuildingCategory.CONSTRUCTION),
- GENERAL(BannerModSettlementBuildingCategory.GENERAL);
+public enum SettlementBuildingProfileSeed {
+ FOOD_PRODUCTION(SettlementBuildingCategory.FOOD),
+ MATERIAL_PRODUCTION(SettlementBuildingCategory.MATERIAL),
+ STORAGE(SettlementBuildingCategory.STORAGE),
+ MARKET(SettlementBuildingCategory.MARKET),
+ CONSTRUCTION(SettlementBuildingCategory.CONSTRUCTION),
+ GENERAL(SettlementBuildingCategory.GENERAL);
- private final BannerModSettlementBuildingCategory category;
+ private final SettlementBuildingCategory category;
- BannerModSettlementBuildingProfileSeed(BannerModSettlementBuildingCategory category) {
+ SettlementBuildingProfileSeed(SettlementBuildingCategory category) {
this.category = category;
}
- public BannerModSettlementBuildingCategory category() {
+ public SettlementBuildingCategory category() {
return this.category;
}
- public static BannerModSettlementBuildingProfileSeed fromWorkArea(AbstractWorkAreaEntity workArea) {
+ public static SettlementBuildingProfileSeed fromWorkArea(AbstractWorkAreaEntity workArea) {
if (workArea instanceof CropArea || workArea instanceof AnimalPenArea || workArea instanceof FishingArea) {
return FOOD_PRODUCTION;
}
@@ -48,7 +48,7 @@ public static BannerModSettlementBuildingProfileSeed fromWorkArea(AbstractWorkAr
return GENERAL;
}
- public static BannerModSettlementBuildingProfileSeed fromBuildingTypeId(String buildingTypeId) {
+ public static SettlementBuildingProfileSeed fromBuildingTypeId(String buildingTypeId) {
if (buildingTypeId == null || buildingTypeId.isBlank()) {
return GENERAL;
}
@@ -65,12 +65,12 @@ public static BannerModSettlementBuildingProfileSeed fromBuildingTypeId(String b
};
}
- public static BannerModSettlementBuildingProfileSeed fromTagName(String name) {
+ public static SettlementBuildingProfileSeed fromTagName(String name) {
if (name == null || name.isBlank()) {
return GENERAL;
}
try {
- return BannerModSettlementBuildingProfileSeed.valueOf(name);
+ return SettlementBuildingProfileSeed.valueOf(name);
} catch (IllegalArgumentException exception) {
return GENERAL;
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementBuildingRecord.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementBuildingRecord.java
similarity index 84%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementBuildingRecord.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementBuildingRecord.java
index f463948b..b9057874 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementBuildingRecord.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementBuildingRecord.java
@@ -11,7 +11,7 @@
import java.util.List;
import java.util.UUID;
-public record BannerModSettlementBuildingRecord(
+public record SettlementBuildingRecord(
UUID buildingUuid,
String buildingTypeId,
BlockPos originPos,
@@ -27,10 +27,10 @@ public record BannerModSettlementBuildingRecord(
boolean stockpileRouteAuthored,
boolean stockpilePortEntrypoint,
List stockpileTypeIds,
- BannerModSettlementBuildingCategory buildingCategory,
- BannerModSettlementBuildingProfileSeed buildingProfileSeed
+ SettlementBuildingCategory buildingCategory,
+ SettlementBuildingProfileSeed buildingProfileSeed
) {
- public BannerModSettlementBuildingRecord {
+ public SettlementBuildingRecord {
residentCapacity = Math.max(0, residentCapacity);
workplaceSlots = Math.max(0, workplaceSlots);
assignedWorkerCount = Math.max(0, assignedWorkerCount);
@@ -38,11 +38,11 @@ public record BannerModSettlementBuildingRecord(
stockpileSlotCapacity = Math.max(0, stockpileSlotCapacity);
assignedResidentUuids = List.copyOf(assignedResidentUuids == null ? List.of() : assignedResidentUuids);
stockpileTypeIds = List.copyOf(stockpileTypeIds == null ? List.of() : stockpileTypeIds);
- buildingProfileSeed = buildingProfileSeed == null ? BannerModSettlementBuildingProfileSeed.fromBuildingTypeId(buildingTypeId) : buildingProfileSeed;
+ buildingProfileSeed = buildingProfileSeed == null ? SettlementBuildingProfileSeed.fromBuildingTypeId(buildingTypeId) : buildingProfileSeed;
buildingCategory = buildingCategory == null ? buildingProfileSeed.category() : buildingCategory;
}
- public BannerModSettlementBuildingRecord(UUID buildingUuid,
+ public SettlementBuildingRecord(UUID buildingUuid,
String buildingTypeId,
BlockPos originPos,
@Nullable UUID ownerUuid,
@@ -67,12 +67,12 @@ public BannerModSettlementBuildingRecord(UUID buildingUuid,
false,
false,
List.of(),
- BannerModSettlementBuildingProfileSeed.fromBuildingTypeId(buildingTypeId).category(),
- BannerModSettlementBuildingProfileSeed.fromBuildingTypeId(buildingTypeId)
+ SettlementBuildingProfileSeed.fromBuildingTypeId(buildingTypeId).category(),
+ SettlementBuildingProfileSeed.fromBuildingTypeId(buildingTypeId)
);
}
- public BannerModSettlementBuildingRecord(UUID buildingUuid,
+ public SettlementBuildingRecord(UUID buildingUuid,
String buildingTypeId,
BlockPos originPos,
@Nullable UUID ownerUuid,
@@ -103,8 +103,8 @@ public BannerModSettlementBuildingRecord(UUID buildingUuid,
stockpileRouteAuthored,
stockpilePortEntrypoint,
stockpileTypeIds,
- BannerModSettlementBuildingProfileSeed.fromBuildingTypeId(buildingTypeId).category(),
- BannerModSettlementBuildingProfileSeed.fromBuildingTypeId(buildingTypeId)
+ SettlementBuildingProfileSeed.fromBuildingTypeId(buildingTypeId).category(),
+ SettlementBuildingProfileSeed.fromBuildingTypeId(buildingTypeId)
);
}
@@ -146,14 +146,14 @@ public CompoundTag toTag() {
return tag;
}
- public static BannerModSettlementBuildingRecord fromTag(CompoundTag tag) {
+ public static SettlementBuildingRecord fromTag(CompoundTag tag) {
UUID ownerUuid = tag.hasUUID("OwnerUuid") ? tag.getUUID("OwnerUuid") : null;
String teamId = tag.contains("TeamId", Tag.TAG_STRING) ? tag.getString("TeamId") : null;
String buildingTypeId = tag.getString("BuildingTypeId");
- BannerModSettlementBuildingProfileSeed profileSeed = tag.contains("BuildingProfileSeed", Tag.TAG_STRING)
- ? BannerModSettlementBuildingProfileSeed.fromTagName(tag.getString("BuildingProfileSeed"))
- : BannerModSettlementBuildingProfileSeed.fromBuildingTypeId(buildingTypeId);
- return new BannerModSettlementBuildingRecord(
+ SettlementBuildingProfileSeed profileSeed = tag.contains("BuildingProfileSeed", Tag.TAG_STRING)
+ ? SettlementBuildingProfileSeed.fromTagName(tag.getString("BuildingProfileSeed"))
+ : SettlementBuildingProfileSeed.fromBuildingTypeId(buildingTypeId);
+ return new SettlementBuildingRecord(
tag.getUUID("BuildingUuid"),
buildingTypeId,
BlockPos.of(tag.getLong("OriginPos")),
@@ -170,7 +170,7 @@ public static BannerModSettlementBuildingRecord fromTag(CompoundTag tag) {
tag.getBoolean("StockpilePortEntrypoint"),
readStockpileTypeIds(tag.getList("StockpileTypeIds", Tag.TAG_STRING)),
tag.contains("BuildingCategory", Tag.TAG_STRING)
- ? BannerModSettlementBuildingCategory.fromTagName(tag.getString("BuildingCategory"))
+ ? SettlementBuildingCategory.fromTagName(tag.getString("BuildingCategory"))
: profileSeed.category(),
profileSeed
);
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementClaimTickService.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementClaimTickService.java
similarity index 79%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementClaimTickService.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementClaimTickService.java
index 0a52d3fe..04a08b35 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementClaimTickService.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementClaimTickService.java
@@ -7,14 +7,14 @@
import com.talhanation.bannermod.settlement.goal.ResidentGoalContext;
import com.talhanation.bannermod.settlement.goal.ResidentTask;
import com.talhanation.bannermod.settlement.goal.impl.WorkResidentGoal;
-import com.talhanation.bannermod.settlement.growth.BannerModSettlementGrowthContext;
-import com.talhanation.bannermod.settlement.growth.BannerModSettlementGrowthManager;
+import com.talhanation.bannermod.settlement.growth.SettlementGrowthContext;
+import com.talhanation.bannermod.settlement.growth.SettlementGrowthManager;
import com.talhanation.bannermod.settlement.growth.PendingProject;
import com.talhanation.bannermod.settlement.household.BannerModHomeAssignmentAdvisor;
import com.talhanation.bannermod.settlement.household.BannerModHomeAssignmentRuntime;
import com.talhanation.bannermod.settlement.household.HomePreference;
import com.talhanation.bannermod.settlement.job.JobExecutionContext;
-import com.talhanation.bannermod.settlement.project.BannerModSettlementProjectRuntime;
+import com.talhanation.bannermod.settlement.project.SettlementProjectRuntime;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrderPublishContext;
import net.minecraft.server.level.ServerLevel;
@@ -25,15 +25,15 @@
import java.util.Set;
import java.util.UUID;
-final class BannerModSettlementClaimTickService {
+final class SettlementClaimTickService {
private static final int MAX_GROWTH_QUEUE_SIZE = 3;
- private BannerModSettlementClaimTickService() {
+ private SettlementClaimTickService() {
}
- static void tickSnapshot(BannerModSettlementOrchestrator.LevelRuntimeState state,
- BannerModSettlementSnapshot snapshot,
+ static void tickSnapshot(SettlementOrchestrator.LevelRuntimeState state,
+ SettlementSnapshot snapshot,
@Nullable BannerModGovernorSnapshot governorSnapshot,
@Nullable ServerLevel level,
long gameTime) {
@@ -41,12 +41,12 @@ static void tickSnapshot(BannerModSettlementOrchestrator.LevelRuntimeState state
return;
}
- BannerModSettlementGrowthContext growthContext = BannerModSettlementGrowthContext.fromSnapshot(
+ SettlementGrowthContext growthContext = SettlementGrowthContext.fromSnapshot(
snapshot,
governorSnapshot,
gameTime
);
- List growthQueue = BannerModSettlementGrowthManager.evaluateGrowthQueue(
+ List growthQueue = SettlementGrowthManager.evaluateGrowthQueue(
growthContext,
MAX_GROWTH_QUEUE_SIZE
);
@@ -56,7 +56,7 @@ static void tickSnapshot(BannerModSettlementOrchestrator.LevelRuntimeState state
null,
snapshot.claimUuid(),
growthQueue,
- BannerModSettlementProjectRuntime.buildAreaResolver(level),
+ SettlementProjectRuntime.buildAreaResolver(level),
gameTime
);
@@ -65,7 +65,7 @@ static void tickSnapshot(BannerModSettlementOrchestrator.LevelRuntimeState state
tickSellerDispatches(state.sellerRuntime, snapshot.marketState(), gameTime);
publishBuildingWorkOrders(state, snapshot, level, gameTime);
- for (BannerModSettlementResidentRecord resident : snapshot.residents()) {
+ for (SettlementResidentRecord resident : snapshot.residents()) {
if (resident == null || resident.residentUuid() == null) {
continue;
}
@@ -75,14 +75,14 @@ static void tickSnapshot(BannerModSettlementOrchestrator.LevelRuntimeState state
}
}
- private static void publishBuildingWorkOrders(BannerModSettlementOrchestrator.LevelRuntimeState state,
- BannerModSettlementSnapshot snapshot,
+ private static void publishBuildingWorkOrders(SettlementOrchestrator.LevelRuntimeState state,
+ SettlementSnapshot snapshot,
@Nullable ServerLevel level,
long gameTime) {
if (state.publisherRegistry.size() == 0) {
return;
}
- for (BannerModSettlementBuildingRecord building : snapshot.buildings()) {
+ for (SettlementBuildingRecord building : snapshot.buildings()) {
if (building == null || building.buildingUuid() == null) {
continue;
}
@@ -99,9 +99,9 @@ private static void publishBuildingWorkOrders(BannerModSettlementOrchestrator.Le
}
private static void assignHomes(BannerModHomeAssignmentRuntime homeRuntime,
- BannerModSettlementSnapshot snapshot,
+ SettlementSnapshot snapshot,
long gameTime) {
- for (BannerModSettlementResidentRecord resident : snapshot.residents()) {
+ for (SettlementResidentRecord resident : snapshot.residents()) {
if (resident == null || resident.residentUuid() == null || homeRuntime.homeFor(resident.residentUuid()).isPresent()) {
continue;
}
@@ -116,16 +116,16 @@ private static void assignHomes(BannerModHomeAssignmentRuntime homeRuntime,
}
private static void tickSellerDispatches(BannerModSellerDispatchRuntime sellerRuntime,
- BannerModSettlementMarketState marketState,
+ SettlementMarketState marketState,
long gameTime) {
Set openMarkets = new HashSet<>();
java.util.Map seededMarketsBySeller = new java.util.LinkedHashMap<>();
- for (BannerModSettlementMarketRecord market : marketState.markets()) {
+ for (SettlementMarketRecord market : marketState.markets()) {
if (market != null && market.open() && market.buildingUuid() != null) {
openMarkets.add(market.buildingUuid());
}
}
- for (BannerModSettlementSellerDispatchRecord seed : marketState.sellerDispatches()) {
+ for (SettlementSellerDispatchRecord seed : marketState.sellerDispatches()) {
if (seed != null && seed.residentUuid() != null && seed.marketUuid() != null) {
seededMarketsBySeller.put(seed.residentUuid(), seed.marketUuid());
}
@@ -144,9 +144,9 @@ private static void tickSellerDispatches(BannerModSellerDispatchRuntime sellerRu
}
}
- for (BannerModSettlementSellerDispatchRecord seed : marketState.sellerDispatches()) {
+ for (SettlementSellerDispatchRecord seed : marketState.sellerDispatches()) {
if (seed == null
- || seed.dispatchState() != BannerModSettlementSellerDispatchState.READY
+ || seed.dispatchState() != SettlementSellerDispatchState.READY
|| seed.residentUuid() == null
|| seed.marketUuid() == null
|| !openMarkets.contains(seed.marketUuid())
@@ -167,9 +167,9 @@ private static void tickSellerDispatches(BannerModSellerDispatchRuntime sellerRu
}
}
- private static void runResidentJobStep(BannerModSettlementOrchestrator.LevelRuntimeState state,
+ private static void runResidentJobStep(SettlementOrchestrator.LevelRuntimeState state,
ResidentGoalContext goalContext) {
- BannerModSettlementResidentRecord resident = goalContext.resident();
+ SettlementResidentRecord resident = goalContext.resident();
if (resident.jobDefinition() == null) {
return;
}
@@ -193,8 +193,8 @@ private static void runResidentJobStep(BannerModSettlementOrchestrator.LevelRunt
});
}
- private static JobExecutionContext jobContext(BannerModSettlementOrchestrator.LevelRuntimeState state,
- BannerModSettlementResidentRecord resident,
+ private static JobExecutionContext jobContext(SettlementOrchestrator.LevelRuntimeState state,
+ SettlementResidentRecord resident,
long gameTime) {
UUID workplaceUuid = resident.jobDefinition() == null || resident.jobDefinition().targetBuildingUuid() == null
? resident.boundWorkAreaUuid()
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementDesiredGoodSeed.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementDesiredGoodSnapshot.java
similarity index 75%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementDesiredGoodSeed.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementDesiredGoodSnapshot.java
index d27d238a..670a0b5b 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementDesiredGoodSeed.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementDesiredGoodSnapshot.java
@@ -3,11 +3,11 @@
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
-public record BannerModSettlementDesiredGoodSeed(
+public record SettlementDesiredGoodSnapshot(
String desiredGoodId,
int driverCount
) {
- public BannerModSettlementDesiredGoodSeed {
+ public SettlementDesiredGoodSnapshot {
desiredGoodId = desiredGoodId == null ? "" : desiredGoodId;
driverCount = Math.max(0, driverCount);
}
@@ -21,8 +21,8 @@ public CompoundTag toTag() {
return tag;
}
- public static BannerModSettlementDesiredGoodSeed fromTag(CompoundTag tag) {
- return new BannerModSettlementDesiredGoodSeed(
+ public static SettlementDesiredGoodSnapshot fromTag(CompoundTag tag) {
+ return new SettlementDesiredGoodSnapshot(
tag.contains("DesiredGoodId", Tag.TAG_STRING) ? tag.getString("DesiredGoodId") : "",
tag.getInt("DriverCount")
);
diff --git a/src/main/java/com/talhanation/bannermod/settlement/SettlementDesiredGoodsSnapshot.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementDesiredGoodsSnapshot.java
new file mode 100644
index 00000000..68ae5530
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementDesiredGoodsSnapshot.java
@@ -0,0 +1,38 @@
+package com.talhanation.bannermod.settlement;
+
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.ListTag;
+import net.minecraft.nbt.Tag;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public record SettlementDesiredGoodsSnapshot(
+ List desiredGoods
+) {
+ public SettlementDesiredGoodsSnapshot {
+ desiredGoods = List.copyOf(desiredGoods == null ? List.of() : desiredGoods);
+ }
+
+ public CompoundTag toTag() {
+ CompoundTag tag = new CompoundTag();
+ ListTag desiredGoodsList = new ListTag();
+ for (SettlementDesiredGoodSnapshot desiredGood : this.desiredGoods) {
+ desiredGoodsList.add(desiredGood.toTag());
+ }
+ tag.put("DesiredGoods", desiredGoodsList);
+ return tag;
+ }
+
+ public static SettlementDesiredGoodsSnapshot fromTag(CompoundTag tag) {
+ List desiredGoods = new ArrayList<>();
+ for (Tag entry : tag.getList("DesiredGoods", Tag.TAG_COMPOUND)) {
+ desiredGoods.add(SettlementDesiredGoodSnapshot.fromTag((CompoundTag) entry));
+ }
+ return new SettlementDesiredGoodsSnapshot(desiredGoods);
+ }
+
+ public static SettlementDesiredGoodsSnapshot empty() {
+ return new SettlementDesiredGoodsSnapshot(List.of());
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementJobHandlerSeed.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementJobHandlerSeed.java
similarity index 75%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementJobHandlerSeed.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementJobHandlerSeed.java
index 0b74e6c1..200b694e 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementJobHandlerSeed.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementJobHandlerSeed.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.settlement;
-public enum BannerModSettlementJobHandlerSeed {
+public enum SettlementJobHandlerSeed {
NONE,
VILLAGE_LIFE,
GOVERNANCE,
@@ -8,7 +8,7 @@ public enum BannerModSettlementJobHandlerSeed {
FLOATING_LABOR_POOL,
ORPHANED_LABOR_RECOVERY;
- public static BannerModSettlementJobHandlerSeed fromTagName(String name) {
+ public static SettlementJobHandlerSeed fromTagName(String name) {
if (name == null || name.isBlank()) {
return NONE;
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementJobTargetSelectionMode.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementJobTargetSelectionMode.java
similarity index 74%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementJobTargetSelectionMode.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementJobTargetSelectionMode.java
index 13e13c6c..e7fcf7ad 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementJobTargetSelectionMode.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementJobTargetSelectionMode.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.settlement;
-public enum BannerModSettlementJobTargetSelectionMode {
+public enum SettlementJobTargetSelectionMode {
NONE,
SERVICE_BUILDING,
SELLER_MARKET_DISPATCH,
@@ -8,7 +8,7 @@ public enum BannerModSettlementJobTargetSelectionMode {
FLOATING_LABOR_POOL,
ORPHANED_SERVICE_BUILDING;
- public static BannerModSettlementJobTargetSelectionMode fromTagName(String name) {
+ public static SettlementJobTargetSelectionMode fromTagName(String name) {
if (name == null || name.isBlank()) {
return NONE;
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementLogisticsDerivationService.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementLogisticsDerivationService.java
similarity index 51%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementLogisticsDerivationService.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementLogisticsDerivationService.java
index 2176ebc6..fa0b92eb 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementLogisticsDerivationService.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementLogisticsDerivationService.java
@@ -8,14 +8,14 @@
import java.util.List;
-final class BannerModSettlementLogisticsDerivationService {
+final class SettlementLogisticsDerivationService {
- private BannerModSettlementLogisticsDerivationService() {
+ private SettlementLogisticsDerivationService() {
}
- static LogisticsResult derive(List buildings,
- List residents,
- BannerModSettlementMarketState marketState,
+ static LogisticsResult derive(List buildings,
+ List residents,
+ SettlementMarketState marketState,
List liveSeaTradeEntrypoints,
List localRoutes,
List reservations,
@@ -23,36 +23,36 @@ static LogisticsResult derive(List buildings,
boolean governedSettlement,
boolean claimedSettlement) {
BannerModSeaTradeSummary.Summary seaTradeSummary = BannerModSeaTradeSummary.summarise(liveSeaTradeEntrypoints);
- BannerModSettlementService.ReservationSignalSeed reservationSignalSeed = BannerModSettlementService.summarizeReservationSignalSeed(
+ SettlementSnapshotRuntime.ReservationSignalSeed reservationSignalSeed = SettlementSnapshotRuntime.summarizeReservationSignalSeed(
buildings,
localRoutes,
reservations
);
- BannerModSettlementStockpileSummary stockpileSummary = BannerModSettlementService.summarizeStockpiles(buildings, liveSeaTradeEntrypoints);
- BannerModSettlementDesiredGoodsSeed desiredGoodsSeed = BannerModSettlementService.summarizeDesiredGoods(
+ SettlementStockpileSummary stockpileSummary = SettlementSnapshotRuntime.summarizeStockpiles(buildings, liveSeaTradeEntrypoints);
+ SettlementDesiredGoodsSnapshot desiredGoodsSnapshot = SettlementSnapshotRuntime.summarizeDesiredGoods(
buildings,
stockpileSummary,
marketState,
seaTradeSummary
);
- BannerModSettlementProjectCandidateSeed projectCandidateSeed = BannerModSettlementService.summarizeProjectCandidate(
+ SettlementProjectCandidateSnapshot projectCandidateSnapshot = SettlementSnapshotRuntime.summarizeProjectCandidate(
buildings,
stockpileSummary,
- desiredGoodsSeed,
+ desiredGoodsSnapshot,
marketState,
governedSettlement,
claimedSettlement
);
- BannerModSettlementTradeRouteHandoffSeed tradeRouteHandoffSeed = BannerModSettlementService.summarizeTradeRouteHandoffSeed(
+ SettlementTradeRouteHandoffSnapshot tradeRouteHandoffSnapshot = SettlementSnapshotRuntime.summarizeTradeRouteHandoffSnapshot(
stockpileSummary,
marketState,
- desiredGoodsSeed,
+ desiredGoodsSnapshot,
reservationSignalSeed,
seaTradeSummary,
localSeaTradeExecutions
);
- BannerModSettlementSupplySignalState supplySignalState = BannerModSettlementService.summarizeSupplySignals(
- desiredGoodsSeed,
+ SettlementSupplySignalState supplySignalState = SettlementSnapshotRuntime.summarizeSupplySignals(
+ desiredGoodsSnapshot,
stockpileSummary,
marketState,
residents,
@@ -62,19 +62,19 @@ static LogisticsResult derive(List buildings,
);
return new LogisticsResult(
stockpileSummary,
- desiredGoodsSeed,
- projectCandidateSeed,
- tradeRouteHandoffSeed,
+ desiredGoodsSnapshot,
+ projectCandidateSnapshot,
+ tradeRouteHandoffSnapshot,
supplySignalState,
reservationSignalSeed
);
}
- record LogisticsResult(BannerModSettlementStockpileSummary stockpileSummary,
- BannerModSettlementDesiredGoodsSeed desiredGoodsSeed,
- BannerModSettlementProjectCandidateSeed projectCandidateSeed,
- BannerModSettlementTradeRouteHandoffSeed tradeRouteHandoffSeed,
- BannerModSettlementSupplySignalState supplySignalState,
- BannerModSettlementService.ReservationSignalSeed reservationSignalSeed) {
+ record LogisticsResult(SettlementStockpileSummary stockpileSummary,
+ SettlementDesiredGoodsSnapshot desiredGoodsSnapshot,
+ SettlementProjectCandidateSnapshot projectCandidateSnapshot,
+ SettlementTradeRouteHandoffSnapshot tradeRouteHandoffSnapshot,
+ SettlementSupplySignalState supplySignalState,
+ SettlementSnapshotRuntime.ReservationSignalSeed reservationSignalSeed) {
}
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementManager.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementManager.java
similarity index 62%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementManager.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementManager.java
index 2e8033a0..28a005c2 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementManager.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementManager.java
@@ -16,24 +16,24 @@
import java.util.Set;
import java.util.UUID;
-public class BannerModSettlementManager extends SavedData {
+public class SettlementManager extends SavedData {
private static final String FILE_ID = "bannermodSettlements";
- private static final SavedData.Factory FACTORY = new SavedData.Factory<>(BannerModSettlementManager::new, BannerModSettlementManager::load);
+ private static final SavedData.Factory FACTORY = new SavedData.Factory<>(SettlementManager::new, SettlementManager::load);
private static final int CURRENT_VERSION = 1;
- private final Map snapshots = new LinkedHashMap<>();
+ private final Map snapshots = new LinkedHashMap<>();
- public static BannerModSettlementManager get(ServerLevel level) {
+ public static SettlementManager get(ServerLevel level) {
return level.getDataStorage().computeIfAbsent(FACTORY, FILE_ID);
}
- public static BannerModSettlementManager load(CompoundTag tag, HolderLookup.Provider registries) {
- SavedDataVersioning.migrate(tag, CURRENT_VERSION, "BannerModSettlementManager");
- BannerModSettlementManager manager = new BannerModSettlementManager();
+ public static SettlementManager load(CompoundTag tag, HolderLookup.Provider registries) {
+ SavedDataVersioning.migrate(tag, CURRENT_VERSION, "SettlementManager");
+ SettlementManager manager = new SettlementManager();
if (tag.contains("Snapshots", Tag.TAG_LIST)) {
ListTag snapshots = tag.getList("Snapshots", Tag.TAG_COMPOUND);
for (Tag entry : snapshots) {
- BannerModSettlementSnapshot snapshot = BannerModSettlementSnapshot.fromTag((CompoundTag) entry);
+ SettlementSnapshot snapshot = SettlementSnapshot.fromTag((CompoundTag) entry);
manager.snapshots.put(snapshot.claimUuid(), snapshot);
}
}
@@ -44,7 +44,7 @@ public static BannerModSettlementManager load(CompoundTag tag, HolderLookup.Prov
public CompoundTag save(CompoundTag tag, HolderLookup.Provider registries) {
SavedDataVersioning.putVersion(tag, CURRENT_VERSION);
ListTag list = new ListTag();
- for (BannerModSettlementSnapshot snapshot : this.snapshots.values()) {
+ for (SettlementSnapshot snapshot : this.snapshots.values()) {
list.add(snapshot.toTag());
}
tag.put("Snapshots", list);
@@ -52,26 +52,26 @@ public CompoundTag save(CompoundTag tag, HolderLookup.Provider registries) {
}
@Nullable
- public BannerModSettlementSnapshot getSnapshot(UUID claimUuid) {
+ public SettlementSnapshot getSnapshot(UUID claimUuid) {
return this.snapshots.get(claimUuid);
}
- public void putSnapshot(BannerModSettlementSnapshot snapshot) {
+ public void putSnapshot(SettlementSnapshot snapshot) {
if (snapshot == null) {
return;
}
- BannerModSettlementSnapshot previous = this.snapshots.put(snapshot.claimUuid(), snapshot);
+ SettlementSnapshot previous = this.snapshots.put(snapshot.claimUuid(), snapshot);
if (!snapshot.equals(previous)) {
this.setDirty();
}
}
@Nullable
- public BannerModSettlementSnapshot removeSnapshot(UUID claimUuid) {
+ public SettlementSnapshot removeSnapshot(UUID claimUuid) {
if (claimUuid == null) {
return null;
}
- BannerModSettlementSnapshot removed = this.snapshots.remove(claimUuid);
+ SettlementSnapshot removed = this.snapshots.remove(claimUuid);
if (removed != null) {
this.setDirty();
}
@@ -91,7 +91,7 @@ public void pruneMissingClaims(Set activeClaimUuids) {
}
}
- public Collection getAllSnapshots() {
+ public Collection getAllSnapshots() {
return this.snapshots.values();
}
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementMarketRecord.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementMarketRecord.java
similarity index 84%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementMarketRecord.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementMarketRecord.java
index 39ecdd46..d28ce2eb 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementMarketRecord.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementMarketRecord.java
@@ -5,14 +5,14 @@
import java.util.UUID;
-public record BannerModSettlementMarketRecord(
+public record SettlementMarketRecord(
UUID buildingUuid,
String marketName,
boolean open,
int totalStorageSlots,
int freeStorageSlots
) {
- public BannerModSettlementMarketRecord {
+ public SettlementMarketRecord {
totalStorageSlots = Math.max(0, totalStorageSlots);
freeStorageSlots = Math.max(0, Math.min(freeStorageSlots, totalStorageSlots));
}
@@ -29,9 +29,9 @@ public CompoundTag toTag() {
return tag;
}
- public static BannerModSettlementMarketRecord fromTag(CompoundTag tag) {
+ public static SettlementMarketRecord fromTag(CompoundTag tag) {
String marketName = tag.contains("MarketName", Tag.TAG_STRING) ? tag.getString("MarketName") : "Market";
- return new BannerModSettlementMarketRecord(
+ return new SettlementMarketRecord(
tag.getUUID("BuildingUuid"),
marketName,
tag.getBoolean("Open"),
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementMarketState.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementMarketState.java
similarity index 67%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementMarketState.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementMarketState.java
index c1355322..1e684349 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementMarketState.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementMarketState.java
@@ -7,17 +7,17 @@
import java.util.ArrayList;
import java.util.List;
-public record BannerModSettlementMarketState(
+public record SettlementMarketState(
int marketCount,
int openMarketCount,
int totalStorageSlots,
int freeStorageSlots,
int sellerDispatchCount,
int readySellerDispatchCount,
- List markets,
- List sellerDispatches
+ List markets,
+ List sellerDispatches
) {
- public BannerModSettlementMarketState {
+ public SettlementMarketState {
marketCount = Math.max(0, marketCount);
openMarketCount = Math.max(0, Math.min(openMarketCount, marketCount));
totalStorageSlots = Math.max(0, totalStorageSlots);
@@ -37,20 +37,20 @@ public CompoundTag toTag() {
tag.putInt("SellerDispatchCount", this.sellerDispatchCount);
tag.putInt("ReadySellerDispatchCount", this.readySellerDispatchCount);
ListTag marketList = new ListTag();
- for (BannerModSettlementMarketRecord market : this.markets) {
+ for (SettlementMarketRecord market : this.markets) {
marketList.add(market.toTag());
}
tag.put("Markets", marketList);
ListTag sellerDispatchList = new ListTag();
- for (BannerModSettlementSellerDispatchRecord sellerDispatch : this.sellerDispatches) {
+ for (SettlementSellerDispatchRecord sellerDispatch : this.sellerDispatches) {
sellerDispatchList.add(sellerDispatch.toTag());
}
tag.put("SellerDispatches", sellerDispatchList);
return tag;
}
- public static BannerModSettlementMarketState fromTag(CompoundTag tag) {
- return new BannerModSettlementMarketState(
+ public static SettlementMarketState fromTag(CompoundTag tag) {
+ return new SettlementMarketState(
tag.getInt("MarketCount"),
tag.getInt("OpenMarketCount"),
tag.getInt("TotalStorageSlots"),
@@ -62,22 +62,22 @@ public static BannerModSettlementMarketState fromTag(CompoundTag tag) {
);
}
- public static BannerModSettlementMarketState empty() {
- return new BannerModSettlementMarketState(0, 0, 0, 0, 0, 0, List.of(), List.of());
+ public static SettlementMarketState empty() {
+ return new SettlementMarketState(0, 0, 0, 0, 0, 0, List.of(), List.of());
}
- private static List readMarkets(ListTag list) {
- List markets = new ArrayList<>();
+ private static List readMarkets(ListTag list) {
+ List markets = new ArrayList<>();
for (Tag entry : list) {
- markets.add(BannerModSettlementMarketRecord.fromTag((CompoundTag) entry));
+ markets.add(SettlementMarketRecord.fromTag((CompoundTag) entry));
}
return markets;
}
- private static List readSellerDispatches(ListTag list) {
- List sellerDispatches = new ArrayList<>();
+ private static List readSellerDispatches(ListTag list) {
+ List sellerDispatches = new ArrayList<>();
for (Tag entry : list) {
- sellerDispatches.add(BannerModSettlementSellerDispatchRecord.fromTag((CompoundTag) entry));
+ sellerDispatches.add(SettlementSellerDispatchRecord.fromTag((CompoundTag) entry));
}
return sellerDispatches;
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementOrchestrator.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementOrchestrator.java
similarity index 83%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementOrchestrator.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementOrchestrator.java
index 9710a6ce..6b4b8ee0 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementOrchestrator.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementOrchestrator.java
@@ -8,7 +8,7 @@
import com.talhanation.bannermod.settlement.household.BannerModHomeAssignmentRuntime;
import com.talhanation.bannermod.settlement.household.BannerModHomeAssignmentSavedData;
import com.talhanation.bannermod.settlement.job.JobHandlerRegistry;
-import com.talhanation.bannermod.settlement.project.BannerModSettlementProjectRuntime;
+import com.talhanation.bannermod.settlement.project.SettlementProjectRuntime;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrderPublisherRegistry;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrderRuntime;
import com.talhanation.bannermod.settlement.workorder.SettlementWorkOrderSavedData;
@@ -24,20 +24,20 @@
import java.util.UUID;
import java.util.WeakHashMap;
-public final class BannerModSettlementOrchestrator {
+public final class SettlementOrchestrator {
private static final WeakHashMap PER_LEVEL = new WeakHashMap<>();
- private BannerModSettlementOrchestrator() {
+ private SettlementOrchestrator() {
}
public static void tick(ServerLevel level,
- BannerModSettlementManager settlementManager,
+ SettlementManager settlementManager,
@Nullable BannerModGovernorManager governorManager) {
tickBatch(level, settlementManager, governorManager, 0, Integer.MAX_VALUE);
}
public static BatchResult tickBatch(ServerLevel level,
- BannerModSettlementManager settlementManager,
+ SettlementManager settlementManager,
@Nullable BannerModGovernorManager governorManager,
int startIndex,
int maxSnapshots) {
@@ -57,7 +57,7 @@ public static BatchResult tickBatch(ServerLevel level,
int clampedStart = Math.max(0, Math.min(startIndex, total));
int endIndex = Math.min(total, clampedStart + maxSnapshots);
for (int i = clampedStart; i < endIndex; i++) {
- BannerModSettlementSnapshot snapshot = settlementManager.getSnapshot(snapshotOrder.get(i));
+ SettlementSnapshot snapshot = settlementManager.getSnapshot(snapshotOrder.get(i));
if (snapshot == null) {
continue;
}
@@ -92,28 +92,28 @@ public static SettlementWorkOrderRuntime workOrderRuntime(ServerLevel level) {
}
static LevelRuntimeState detachedStateForTests(JobHandlerRegistry jobHandlerRegistry) {
- return LevelRuntimeState.create(BannerModSettlementProjectRuntime.detachedForTests(), jobHandlerRegistry);
+ return LevelRuntimeState.create(SettlementProjectRuntime.detachedForTests(), jobHandlerRegistry);
}
static void tickSnapshot(LevelRuntimeState state,
- BannerModSettlementSnapshot snapshot,
+ SettlementSnapshot snapshot,
@Nullable BannerModGovernorSnapshot governorSnapshot,
long gameTime) {
tickSnapshot(state, snapshot, governorSnapshot, null, gameTime);
}
static void tickSnapshot(LevelRuntimeState state,
- BannerModSettlementSnapshot snapshot,
+ SettlementSnapshot snapshot,
@Nullable BannerModGovernorSnapshot governorSnapshot,
@Nullable ServerLevel level,
long gameTime) {
- BannerModSettlementClaimTickService.tickSnapshot(state, snapshot, governorSnapshot, level, gameTime);
+ SettlementClaimTickService.tickSnapshot(state, snapshot, governorSnapshot, level, gameTime);
}
private static synchronized LevelRuntimeState runtimeState(ServerLevel level) {
return PER_LEVEL.computeIfAbsent(level,
ignored -> LevelRuntimeState.create(
- BannerModSettlementProjectRuntime.forServer(level),
+ SettlementProjectRuntime.forServer(level),
JobHandlerRegistry.defaults(),
SettlementWorkOrderSavedData.get(level).runtime(),
BannerModHomeAssignmentSavedData.get(level).runtime(),
@@ -122,7 +122,7 @@ private static synchronized LevelRuntimeState runtimeState(ServerLevel level) {
}
static final class LevelRuntimeState {
- final BannerModSettlementProjectRuntime projectRuntime;
+ final SettlementProjectRuntime projectRuntime;
final BannerModHomeAssignmentRuntime homeRuntime;
final BannerModSellerDispatchRuntime sellerRuntime;
final MutableMarketStateSupplier marketStateSupplier;
@@ -133,7 +133,7 @@ static final class LevelRuntimeState {
final SettlementWorkOrderPublisherRegistry publisherRegistry;
private final List orchestratorSnapshotOrder = new ArrayList<>();
- private LevelRuntimeState(BannerModSettlementProjectRuntime projectRuntime,
+ private LevelRuntimeState(SettlementProjectRuntime projectRuntime,
BannerModHomeAssignmentRuntime homeRuntime,
BannerModSellerDispatchRuntime sellerRuntime,
MutableMarketStateSupplier marketStateSupplier,
@@ -153,10 +153,10 @@ private LevelRuntimeState(BannerModSettlementProjectRuntime projectRuntime,
this.publisherRegistry = publisherRegistry;
}
- List snapshotOrderForBatch(BannerModSettlementManager settlementManager, int startIndex) {
+ List snapshotOrderForBatch(SettlementManager settlementManager, int startIndex) {
if (startIndex <= 0 || this.orchestratorSnapshotOrder.isEmpty()) {
this.orchestratorSnapshotOrder.clear();
- for (BannerModSettlementSnapshot snapshot : settlementManager.getAllSnapshots()) {
+ for (SettlementSnapshot snapshot : settlementManager.getAllSnapshots()) {
if (snapshot != null && snapshot.claimUuid() != null) {
this.orchestratorSnapshotOrder.add(snapshot.claimUuid());
}
@@ -166,20 +166,20 @@ List snapshotOrderForBatch(BannerModSettlementManager settlementManager, i
return this.orchestratorSnapshotOrder;
}
- private static LevelRuntimeState create(BannerModSettlementProjectRuntime projectRuntime,
+ private static LevelRuntimeState create(SettlementProjectRuntime projectRuntime,
JobHandlerRegistry jobHandlerRegistry) {
return create(projectRuntime, jobHandlerRegistry, new SettlementWorkOrderRuntime(),
new BannerModHomeAssignmentRuntime(), new BannerModSellerDispatchRuntime());
}
- private static LevelRuntimeState create(BannerModSettlementProjectRuntime projectRuntime,
+ private static LevelRuntimeState create(SettlementProjectRuntime projectRuntime,
JobHandlerRegistry jobHandlerRegistry,
SettlementWorkOrderRuntime workOrderRuntime) {
return create(projectRuntime, jobHandlerRegistry, workOrderRuntime,
new BannerModHomeAssignmentRuntime(), new BannerModSellerDispatchRuntime());
}
- private static LevelRuntimeState create(BannerModSettlementProjectRuntime projectRuntime,
+ private static LevelRuntimeState create(SettlementProjectRuntime projectRuntime,
JobHandlerRegistry jobHandlerRegistry,
SettlementWorkOrderRuntime workOrderRuntime,
BannerModHomeAssignmentRuntime homeRuntime,
@@ -205,16 +205,16 @@ private static LevelRuntimeState create(BannerModSettlementProjectRuntime projec
}
}
- static final class MutableMarketStateSupplier implements java.util.function.Supplier {
- private BannerModSettlementMarketState marketState = BannerModSettlementMarketState.empty();
+ static final class MutableMarketStateSupplier implements java.util.function.Supplier {
+ private SettlementMarketState marketState = SettlementMarketState.empty();
@Override
- public BannerModSettlementMarketState get() {
+ public SettlementMarketState get() {
return this.marketState;
}
- void set(@Nullable BannerModSettlementMarketState marketState) {
- this.marketState = marketState == null ? BannerModSettlementMarketState.empty() : marketState;
+ void set(@Nullable SettlementMarketState marketState) {
+ this.marketState = marketState == null ? SettlementMarketState.empty() : marketState;
}
}
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementProjectCandidateSeed.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementProjectCandidateSnapshot.java
similarity index 73%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementProjectCandidateSeed.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementProjectCandidateSnapshot.java
index de0d3c8a..09b45151 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementProjectCandidateSeed.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementProjectCandidateSnapshot.java
@@ -9,15 +9,15 @@
import java.util.ArrayList;
import java.util.List;
-public record BannerModSettlementProjectCandidateSeed(
+public record SettlementProjectCandidateSnapshot(
String candidateId,
- @Nullable BannerModSettlementBuildingProfileSeed targetBuildingProfileSeed,
+ @Nullable SettlementBuildingProfileSeed targetBuildingProfileSeed,
int priority,
boolean governedSettlement,
boolean claimedSettlement,
List driverIds
) {
- public BannerModSettlementProjectCandidateSeed {
+ public SettlementProjectCandidateSnapshot {
candidateId = candidateId == null || candidateId.isBlank() ? "none" : candidateId;
priority = Math.max(0, priority);
driverIds = List.copyOf(driverIds == null ? List.of() : driverIds);
@@ -42,11 +42,11 @@ public CompoundTag toTag() {
return tag;
}
- public static BannerModSettlementProjectCandidateSeed fromTag(CompoundTag tag) {
- BannerModSettlementBuildingProfileSeed targetBuildingProfileSeed = tag.contains("TargetBuildingProfileSeed", Tag.TAG_STRING)
- ? BannerModSettlementBuildingProfileSeed.fromTagName(tag.getString("TargetBuildingProfileSeed"))
+ public static SettlementProjectCandidateSnapshot fromTag(CompoundTag tag) {
+ SettlementBuildingProfileSeed targetBuildingProfileSeed = tag.contains("TargetBuildingProfileSeed", Tag.TAG_STRING)
+ ? SettlementBuildingProfileSeed.fromTagName(tag.getString("TargetBuildingProfileSeed"))
: null;
- return new BannerModSettlementProjectCandidateSeed(
+ return new SettlementProjectCandidateSnapshot(
tag.contains("CandidateId", Tag.TAG_STRING) ? tag.getString("CandidateId") : "none",
targetBuildingProfileSeed,
tag.getInt("Priority"),
@@ -56,8 +56,8 @@ public static BannerModSettlementProjectCandidateSeed fromTag(CompoundTag tag) {
);
}
- public static BannerModSettlementProjectCandidateSeed empty() {
- return new BannerModSettlementProjectCandidateSeed("none", null, 0, false, false, List.of());
+ public static SettlementProjectCandidateSnapshot empty() {
+ return new SettlementProjectCandidateSnapshot("none", null, 0, false, false, List.of());
}
private static List readDriverIds(ListTag list) {
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentAssignmentState.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentAssignmentState.java
similarity index 72%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentAssignmentState.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementResidentAssignmentState.java
index 777cd7c3..66c1ad67 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentAssignmentState.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentAssignmentState.java
@@ -1,12 +1,12 @@
package com.talhanation.bannermod.settlement;
-public enum BannerModSettlementResidentAssignmentState {
+public enum SettlementResidentAssignmentState {
NOT_APPLICABLE,
UNASSIGNED,
ASSIGNED_LOCAL_BUILDING,
ASSIGNED_MISSING_BUILDING;
- public static BannerModSettlementResidentAssignmentState fromTagName(String name) {
+ public static SettlementResidentAssignmentState fromTagName(String name) {
if (name == null || name.isBlank()) {
return NOT_APPLICABLE;
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentJobDefinition.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentJobDefinition.java
new file mode 100644
index 00000000..1207eb58
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentJobDefinition.java
@@ -0,0 +1,96 @@
+package com.talhanation.bannermod.settlement;
+
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.Tag;
+
+import javax.annotation.Nullable;
+import java.util.UUID;
+
+public record SettlementResidentJobDefinition(
+ SettlementJobHandlerSeed handlerSeed,
+ @Nullable UUID targetBuildingUuid,
+ @Nullable String targetBuildingTypeId,
+ @Nullable SettlementBuildingCategory targetBuildingCategory,
+ @Nullable SettlementBuildingProfileSeed targetBuildingProfileSeed
+) {
+ public CompoundTag toTag() {
+ CompoundTag tag = new CompoundTag();
+ tag.putString("HandlerSeed", this.handlerSeed.name());
+ if (this.targetBuildingUuid != null) {
+ tag.putUUID("TargetBuildingUuid", this.targetBuildingUuid);
+ }
+ if (this.targetBuildingTypeId != null && !this.targetBuildingTypeId.isBlank()) {
+ tag.putString("TargetBuildingTypeId", this.targetBuildingTypeId);
+ }
+ if (this.targetBuildingCategory != null) {
+ tag.putString("TargetBuildingCategory", this.targetBuildingCategory.name());
+ }
+ if (this.targetBuildingProfileSeed != null) {
+ tag.putString("TargetBuildingProfileSeed", this.targetBuildingProfileSeed.name());
+ }
+ return tag;
+ }
+
+ public static SettlementResidentJobDefinition fromTag(CompoundTag tag) {
+ SettlementJobHandlerSeed handlerSeed = tag.contains("HandlerSeed", Tag.TAG_STRING)
+ ? SettlementJobHandlerSeed.fromTagName(tag.getString("HandlerSeed"))
+ : SettlementJobHandlerSeed.NONE;
+ UUID targetBuildingUuid = tag.hasUUID("TargetBuildingUuid") ? tag.getUUID("TargetBuildingUuid") : null;
+ String targetBuildingTypeId = tag.contains("TargetBuildingTypeId", Tag.TAG_STRING)
+ ? tag.getString("TargetBuildingTypeId")
+ : null;
+ SettlementBuildingCategory targetBuildingCategory = tag.contains("TargetBuildingCategory", Tag.TAG_STRING)
+ ? SettlementBuildingCategory.fromTagName(tag.getString("TargetBuildingCategory"))
+ : null;
+ SettlementBuildingProfileSeed targetBuildingProfileSeed = tag.contains("TargetBuildingProfileSeed", Tag.TAG_STRING)
+ ? SettlementBuildingProfileSeed.fromTagName(tag.getString("TargetBuildingProfileSeed"))
+ : null;
+ return new SettlementResidentJobDefinition(handlerSeed, targetBuildingUuid, targetBuildingTypeId, targetBuildingCategory, targetBuildingProfileSeed);
+ }
+
+ public static SettlementResidentJobDefinition defaultFor(SettlementResidentRole role,
+ SettlementResidentRuntimeRoleState runtimeRoleState,
+ SettlementResidentServiceContract serviceContract,
+ @Nullable SettlementBuildingRecord building) {
+ return switch (runtimeRoleState) {
+ case VILLAGE_LIFE -> new SettlementResidentJobDefinition(SettlementJobHandlerSeed.VILLAGE_LIFE, null, null, null, null);
+ case GOVERNANCE -> new SettlementResidentJobDefinition(SettlementJobHandlerSeed.GOVERNANCE, null, null, null, null);
+ case LOCAL_LABOR -> new SettlementResidentJobDefinition(
+ resolveLocalLaborHandler(role, serviceContract),
+ serviceContract.serviceBuildingUuid(),
+ resolveBuildingTypeId(serviceContract, building),
+ building == null ? null : building.buildingCategory(),
+ building == null ? null : building.buildingProfileSeed()
+ );
+ case FLOATING_LABOR -> new SettlementResidentJobDefinition(SettlementJobHandlerSeed.FLOATING_LABOR_POOL, null, null, null, null);
+ case ORPHANED_LABOR_ASSIGNMENT -> new SettlementResidentJobDefinition(
+ SettlementJobHandlerSeed.ORPHANED_LABOR_RECOVERY,
+ serviceContract.serviceBuildingUuid(),
+ serviceContract.serviceBuildingTypeId(),
+ null,
+ null
+ );
+ };
+ }
+
+ private static SettlementJobHandlerSeed resolveLocalLaborHandler(SettlementResidentRole role,
+ SettlementResidentServiceContract serviceContract) {
+ if (role == SettlementResidentRole.CONTROLLED_WORKER
+ && serviceContract.actorState() == SettlementServiceActorState.LOCAL_BUILDING_SERVICE) {
+ return SettlementJobHandlerSeed.LOCAL_BUILDING_LABOR;
+ }
+ return SettlementJobHandlerSeed.NONE;
+ }
+
+ private static String resolveBuildingTypeId(SettlementResidentServiceContract serviceContract,
+ @Nullable SettlementBuildingRecord building) {
+ if (building != null) {
+ return building.buildingTypeId();
+ }
+ return serviceContract.serviceBuildingTypeId();
+ }
+
+ public static SettlementResidentJobDefinition none() {
+ return new SettlementResidentJobDefinition(SettlementJobHandlerSeed.NONE, null, null, null, null);
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentJobTargetSelectionState.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentJobTargetSelectionState.java
new file mode 100644
index 00000000..1face7c1
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentJobTargetSelectionState.java
@@ -0,0 +1,76 @@
+package com.talhanation.bannermod.settlement;
+
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.Tag;
+
+import javax.annotation.Nullable;
+import java.util.UUID;
+
+public record SettlementResidentJobTargetSelectionState(
+ SettlementJobTargetSelectionMode selectionMode,
+ @Nullable UUID targetMarketUuid,
+ @Nullable String targetMarketName
+) {
+ public CompoundTag toTag() {
+ CompoundTag tag = new CompoundTag();
+ tag.putString("SelectionMode", this.selectionMode.name());
+ if (this.targetMarketUuid != null) {
+ tag.putUUID("TargetMarketUuid", this.targetMarketUuid);
+ }
+ if (this.targetMarketName != null && !this.targetMarketName.isBlank()) {
+ tag.putString("TargetMarketName", this.targetMarketName);
+ }
+ return tag;
+ }
+
+ public static SettlementResidentJobTargetSelectionState fromTag(CompoundTag tag) {
+ SettlementJobTargetSelectionMode selectionMode = tag.contains("SelectionMode", Tag.TAG_STRING)
+ ? SettlementJobTargetSelectionMode.fromTagName(tag.getString("SelectionMode"))
+ : SettlementJobTargetSelectionMode.NONE;
+ UUID targetMarketUuid = tag.hasUUID("TargetMarketUuid") ? tag.getUUID("TargetMarketUuid") : null;
+ String targetMarketName = tag.contains("TargetMarketName", Tag.TAG_STRING)
+ ? tag.getString("TargetMarketName")
+ : null;
+ return new SettlementResidentJobTargetSelectionState(selectionMode, targetMarketUuid, targetMarketName);
+ }
+
+ public static SettlementResidentJobTargetSelectionState defaultFor(UUID residentUuid,
+ SettlementResidentJobDefinition jobDefinition,
+ SettlementResidentServiceContract serviceContract,
+ SettlementMarketState marketState) {
+ SettlementSellerDispatchRecord sellerDispatch = findSellerDispatch(residentUuid, marketState);
+ if (sellerDispatch != null) {
+ return new SettlementResidentJobTargetSelectionState(
+ sellerDispatch.dispatchState() == SettlementSellerDispatchState.READY
+ ? SettlementJobTargetSelectionMode.SELLER_MARKET_DISPATCH
+ : SettlementJobTargetSelectionMode.SELLER_MARKET_CLOSED,
+ sellerDispatch.marketUuid(),
+ sellerDispatch.marketName()
+ );
+ }
+
+ return switch (jobDefinition.handlerSeed()) {
+ case LOCAL_BUILDING_LABOR -> serviceContract.actorState() == SettlementServiceActorState.LOCAL_BUILDING_SERVICE
+ ? new SettlementResidentJobTargetSelectionState(SettlementJobTargetSelectionMode.SERVICE_BUILDING, null, null)
+ : none();
+ case FLOATING_LABOR_POOL -> new SettlementResidentJobTargetSelectionState(SettlementJobTargetSelectionMode.FLOATING_LABOR_POOL, null, null);
+ case ORPHANED_LABOR_RECOVERY -> new SettlementResidentJobTargetSelectionState(SettlementJobTargetSelectionMode.ORPHANED_SERVICE_BUILDING, null, null);
+ default -> none();
+ };
+ }
+
+ public static SettlementResidentJobTargetSelectionState none() {
+ return new SettlementResidentJobTargetSelectionState(SettlementJobTargetSelectionMode.NONE, null, null);
+ }
+
+ @Nullable
+ private static SettlementSellerDispatchRecord findSellerDispatch(UUID residentUuid,
+ SettlementMarketState marketState) {
+ for (SettlementSellerDispatchRecord sellerDispatch : marketState.sellerDispatches()) {
+ if (sellerDispatch.residentUuid().equals(residentUuid)) {
+ return sellerDispatch;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentMode.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentMode.java
similarity index 66%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentMode.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementResidentMode.java
index e87fe441..add9ab11 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentMode.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentMode.java
@@ -3,11 +3,11 @@
import javax.annotation.Nullable;
import java.util.UUID;
-public enum BannerModSettlementResidentMode {
+public enum SettlementResidentMode {
SETTLEMENT_RESIDENT,
PROJECTED_CONTROLLED_WORKER;
- public static BannerModSettlementResidentMode fromTagName(@Nullable String name) {
+ public static SettlementResidentMode fromTagName(@Nullable String name) {
if (name == null || name.isBlank()) {
return SETTLEMENT_RESIDENT;
}
@@ -18,9 +18,9 @@ public static BannerModSettlementResidentMode fromTagName(@Nullable String name)
}
}
- public static BannerModSettlementResidentMode defaultFor(BannerModSettlementResidentRole role,
+ public static SettlementResidentMode defaultFor(SettlementResidentRole role,
@Nullable UUID ownerUuid) {
- return role == BannerModSettlementResidentRole.CONTROLLED_WORKER
+ return role == SettlementResidentRole.CONTROLLED_WORKER
? PROJECTED_CONTROLLED_WORKER
: SETTLEMENT_RESIDENT;
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentRecord.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentRecord.java
new file mode 100644
index 00000000..31a71582
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentRecord.java
@@ -0,0 +1,286 @@
+package com.talhanation.bannermod.settlement;
+
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.Tag;
+
+import javax.annotation.Nullable;
+import java.util.UUID;
+
+public record SettlementResidentRecord(
+ UUID residentUuid,
+ SettlementResidentRole role,
+ SettlementResidentScheduleSeed scheduleSeed,
+ SettlementResidentScheduleWindowSeed scheduleWindowSeed,
+ SettlementResidentRuntimeRoleState runtimeRoleState,
+ SettlementResidentServiceContract serviceContract,
+ SettlementResidentJobDefinition jobDefinition,
+ SettlementResidentJobTargetSelectionState jobTargetSelectionState,
+ SettlementResidentMode residentMode,
+ @Nullable UUID ownerUuid,
+ @Nullable String teamId,
+ @Nullable UUID boundWorkAreaUuid,
+ SettlementResidentAssignmentState assignmentState,
+ SettlementResidentRoleProfile roleProfile,
+ SettlementResidentSchedulePolicy schedulePolicy
+) {
+ public SettlementResidentRecord(UUID residentUuid,
+ SettlementResidentRole role,
+ SettlementResidentScheduleSeed scheduleSeed,
+ SettlementResidentScheduleWindowSeed scheduleWindowSeed,
+ SettlementResidentRuntimeRoleState runtimeRoleState,
+ SettlementResidentServiceContract serviceContract,
+ SettlementResidentJobDefinition jobDefinition,
+ SettlementResidentJobTargetSelectionState jobTargetSelectionState,
+ SettlementResidentMode residentMode,
+ @Nullable UUID ownerUuid,
+ @Nullable String teamId,
+ @Nullable UUID boundWorkAreaUuid,
+ SettlementResidentAssignmentState assignmentState,
+ SettlementResidentRoleProfile roleProfile) {
+ this(
+ residentUuid,
+ role,
+ scheduleSeed,
+ scheduleWindowSeed,
+ runtimeRoleState,
+ serviceContract,
+ jobDefinition,
+ jobTargetSelectionState,
+ residentMode,
+ ownerUuid,
+ teamId,
+ boundWorkAreaUuid,
+ assignmentState,
+ roleProfile,
+ SettlementResidentSchedulePolicy.defaultFor(scheduleSeed, scheduleWindowSeed, runtimeRoleState, roleProfile)
+ );
+ }
+
+ public SettlementResidentRecord(UUID residentUuid,
+ SettlementResidentRole role,
+ SettlementResidentScheduleSeed scheduleSeed,
+ SettlementResidentScheduleWindowSeed scheduleWindowSeed,
+ SettlementResidentRuntimeRoleState runtimeRoleState,
+ SettlementResidentServiceContract serviceContract,
+ SettlementResidentJobDefinition jobDefinition,
+ SettlementResidentJobTargetSelectionState jobTargetSelectionState,
+ SettlementResidentMode residentMode,
+ @Nullable UUID ownerUuid,
+ @Nullable String teamId,
+ @Nullable UUID boundWorkAreaUuid,
+ SettlementResidentAssignmentState assignmentState) {
+ this(
+ residentUuid,
+ role,
+ scheduleSeed,
+ scheduleWindowSeed,
+ runtimeRoleState,
+ serviceContract,
+ jobDefinition,
+ jobTargetSelectionState,
+ residentMode,
+ ownerUuid,
+ teamId,
+ boundWorkAreaUuid,
+ assignmentState,
+ SettlementResidentRoleProfile.defaultFor(role, runtimeRoleState, residentMode, assignmentState)
+ );
+ }
+
+ public SettlementResidentRecord(UUID residentUuid,
+ SettlementResidentRole role,
+ SettlementResidentScheduleSeed scheduleSeed,
+ SettlementResidentScheduleWindowSeed scheduleWindowSeed,
+ SettlementResidentRuntimeRoleState runtimeRoleState,
+ SettlementResidentServiceContract serviceContract,
+ SettlementResidentJobDefinition jobDefinition,
+ SettlementResidentMode residentMode,
+ @Nullable UUID ownerUuid,
+ @Nullable String teamId,
+ @Nullable UUID boundWorkAreaUuid,
+ SettlementResidentAssignmentState assignmentState) {
+ this(
+ residentUuid,
+ role,
+ scheduleSeed,
+ scheduleWindowSeed,
+ runtimeRoleState,
+ serviceContract,
+ jobDefinition,
+ SettlementResidentJobTargetSelectionState.defaultFor(residentUuid, jobDefinition, serviceContract, SettlementMarketState.empty()),
+ residentMode,
+ ownerUuid,
+ teamId,
+ boundWorkAreaUuid,
+ assignmentState,
+ SettlementResidentRoleProfile.defaultFor(role, runtimeRoleState, residentMode, assignmentState)
+ );
+ }
+
+ public SettlementResidentRecord(UUID residentUuid,
+ SettlementResidentRole role,
+ SettlementResidentScheduleSeed scheduleSeed,
+ SettlementResidentRuntimeRoleState runtimeRoleState,
+ SettlementResidentServiceContract serviceContract,
+ SettlementResidentMode residentMode,
+ @Nullable UUID ownerUuid,
+ @Nullable String teamId,
+ @Nullable UUID boundWorkAreaUuid,
+ SettlementResidentAssignmentState assignmentState) {
+ this(
+ residentUuid,
+ role,
+ scheduleSeed,
+ SettlementResidentScheduleWindowSeed.defaultFor(scheduleSeed, runtimeRoleState),
+ runtimeRoleState,
+ serviceContract,
+ SettlementResidentJobDefinition.defaultFor(role, runtimeRoleState, serviceContract, null),
+ SettlementResidentJobTargetSelectionState.defaultFor(
+ residentUuid,
+ SettlementResidentJobDefinition.defaultFor(role, runtimeRoleState, serviceContract, null),
+ serviceContract,
+ SettlementMarketState.empty()
+ ),
+ residentMode,
+ ownerUuid,
+ teamId,
+ boundWorkAreaUuid,
+ assignmentState,
+ SettlementResidentRoleProfile.defaultFor(role, runtimeRoleState, residentMode, assignmentState)
+ );
+ }
+
+ public SettlementResidentRecord(UUID residentUuid,
+ SettlementResidentRole role,
+ SettlementResidentScheduleSeed scheduleSeed,
+ SettlementResidentScheduleWindowSeed scheduleWindowSeed,
+ SettlementResidentRuntimeRoleState runtimeRoleState,
+ SettlementResidentServiceContract serviceContract,
+ SettlementResidentMode residentMode,
+ @Nullable UUID ownerUuid,
+ @Nullable String teamId,
+ @Nullable UUID boundWorkAreaUuid,
+ SettlementResidentAssignmentState assignmentState) {
+ this(
+ residentUuid,
+ role,
+ scheduleSeed,
+ scheduleWindowSeed,
+ runtimeRoleState,
+ serviceContract,
+ SettlementResidentJobDefinition.defaultFor(role, runtimeRoleState, serviceContract, null),
+ SettlementResidentJobTargetSelectionState.defaultFor(
+ residentUuid,
+ SettlementResidentJobDefinition.defaultFor(role, runtimeRoleState, serviceContract, null),
+ serviceContract,
+ SettlementMarketState.empty()
+ ),
+ residentMode,
+ ownerUuid,
+ teamId,
+ boundWorkAreaUuid,
+ assignmentState,
+ SettlementResidentRoleProfile.defaultFor(role, runtimeRoleState, residentMode, assignmentState)
+ );
+ }
+
+ public CompoundTag toTag() {
+ CompoundTag tag = new CompoundTag();
+ tag.putUUID("ResidentUuid", this.residentUuid);
+ tag.putString("Role", this.role.name());
+ tag.putString("ScheduleSeed", this.scheduleSeed.name());
+ tag.putString("ScheduleWindowSeed", this.scheduleWindowSeed.name());
+ tag.putString("RuntimeRoleSeed", this.runtimeRoleState.name());
+ tag.put("ServiceContract", this.serviceContract.toTag());
+ tag.put("JobDefinition", this.jobDefinition.toTag());
+ tag.put("JobTargetSelectionSeed", this.jobTargetSelectionState.toTag());
+ tag.putString("ResidentMode", this.residentMode.name());
+ if (this.ownerUuid != null) {
+ tag.putUUID("OwnerUuid", this.ownerUuid);
+ }
+ if (this.teamId != null && !this.teamId.isBlank()) {
+ tag.putString("TeamId", this.teamId);
+ }
+ if (this.boundWorkAreaUuid != null) {
+ tag.putUUID("BoundWorkAreaUuid", this.boundWorkAreaUuid);
+ }
+ tag.putString("AssignmentState", this.assignmentState.name());
+ tag.put("RoleProfile", this.roleProfile.toTag());
+ tag.put("SchedulePolicy", this.schedulePolicy.toTag());
+ return tag;
+ }
+
+ public static SettlementResidentRecord fromTag(CompoundTag tag) {
+ SettlementResidentRole role = SettlementResidentRole.fromTagName(tag.getString("Role"));
+ UUID ownerUuid = tag.hasUUID("OwnerUuid") ? tag.getUUID("OwnerUuid") : null;
+ String teamId = tag.contains("TeamId", Tag.TAG_STRING) ? tag.getString("TeamId") : null;
+ UUID boundWorkAreaUuid = tag.hasUUID("BoundWorkAreaUuid") ? tag.getUUID("BoundWorkAreaUuid") : null;
+ SettlementResidentScheduleSeed scheduleSeed = tag.contains("ScheduleSeed", Tag.TAG_STRING)
+ ? scheduleSeedFromTagName(tag.getString("ScheduleSeed"), role, boundWorkAreaUuid)
+ : SettlementResidentScheduleSeed.defaultFor(role, boundWorkAreaUuid);
+ SettlementResidentMode residentMode = tag.contains("ResidentMode", Tag.TAG_STRING)
+ ? SettlementResidentMode.fromTagName(tag.getString("ResidentMode"))
+ : SettlementResidentMode.defaultFor(role, ownerUuid);
+ SettlementResidentAssignmentState assignmentState = tag.contains("AssignmentState", Tag.TAG_STRING)
+ ? SettlementResidentAssignmentState.fromTagName(tag.getString("AssignmentState"))
+ : defaultAssignmentState(role, boundWorkAreaUuid);
+ SettlementResidentRuntimeRoleState runtimeRoleState = tag.contains("RuntimeRoleSeed", Tag.TAG_STRING)
+ ? SettlementResidentRuntimeRoleState.fromTagName(tag.getString("RuntimeRoleSeed"))
+ : SettlementResidentRuntimeRoleState.defaultFor(role, scheduleSeed, residentMode, assignmentState);
+ SettlementResidentScheduleWindowSeed scheduleWindowSeed = tag.contains("ScheduleWindowSeed", Tag.TAG_STRING)
+ ? SettlementResidentScheduleWindowSeed.fromTagName(tag.getString("ScheduleWindowSeed"))
+ : SettlementResidentScheduleWindowSeed.defaultFor(scheduleSeed, runtimeRoleState);
+ SettlementResidentServiceContract serviceContract = tag.contains("ServiceContract", Tag.TAG_COMPOUND)
+ ? SettlementResidentServiceContract.fromTag(tag.getCompound("ServiceContract"))
+ : SettlementResidentServiceContract.defaultFor(role, residentMode, assignmentState, boundWorkAreaUuid, null);
+ SettlementResidentJobDefinition jobDefinition = tag.contains("JobDefinition", Tag.TAG_COMPOUND)
+ ? SettlementResidentJobDefinition.fromTag(tag.getCompound("JobDefinition"))
+ : SettlementResidentJobDefinition.defaultFor(role, runtimeRoleState, serviceContract, null);
+ SettlementResidentJobTargetSelectionState jobTargetSelectionState = tag.contains("JobTargetSelectionSeed", Tag.TAG_COMPOUND)
+ ? SettlementResidentJobTargetSelectionState.fromTag(tag.getCompound("JobTargetSelectionSeed"))
+ : SettlementResidentJobTargetSelectionState.defaultFor(tag.getUUID("ResidentUuid"), jobDefinition, serviceContract, SettlementMarketState.empty());
+ SettlementResidentRoleProfile roleProfile = tag.contains("RoleProfile", Tag.TAG_COMPOUND)
+ ? SettlementResidentRoleProfile.fromTag(tag.getCompound("RoleProfile"))
+ : SettlementResidentRoleProfile.defaultFor(role, runtimeRoleState, residentMode, assignmentState);
+ SettlementResidentSchedulePolicy schedulePolicy = tag.contains("SchedulePolicy", Tag.TAG_COMPOUND)
+ ? SettlementResidentSchedulePolicy.fromTag(tag.getCompound("SchedulePolicy"))
+ : SettlementResidentSchedulePolicy.defaultFor(scheduleSeed, scheduleWindowSeed, runtimeRoleState, roleProfile);
+ return new SettlementResidentRecord(
+ tag.getUUID("ResidentUuid"),
+ role,
+ scheduleSeed,
+ scheduleWindowSeed,
+ runtimeRoleState,
+ serviceContract,
+ jobDefinition,
+ jobTargetSelectionState,
+ residentMode,
+ ownerUuid,
+ teamId,
+ boundWorkAreaUuid,
+ assignmentState,
+ roleProfile,
+ schedulePolicy
+ );
+ }
+
+ private static SettlementResidentAssignmentState defaultAssignmentState(SettlementResidentRole role,
+ @Nullable UUID boundWorkAreaUuid) {
+ if (role != SettlementResidentRole.CONTROLLED_WORKER) {
+ return SettlementResidentAssignmentState.NOT_APPLICABLE;
+ }
+ return boundWorkAreaUuid == null
+ ? SettlementResidentAssignmentState.UNASSIGNED
+ : SettlementResidentAssignmentState.ASSIGNED_LOCAL_BUILDING;
+ }
+
+ private static SettlementResidentScheduleSeed scheduleSeedFromTagName(String name,
+ SettlementResidentRole role,
+ @Nullable UUID boundWorkAreaUuid) {
+ try {
+ return SettlementResidentScheduleSeed.valueOf(name);
+ } catch (IllegalArgumentException exception) {
+ return SettlementResidentScheduleSeed.defaultFor(role, boundWorkAreaUuid);
+ }
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentRole.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentRole.java
similarity index 73%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentRole.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementResidentRole.java
index 3301cea8..211dabdf 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentRole.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentRole.java
@@ -1,11 +1,11 @@
package com.talhanation.bannermod.settlement;
-public enum BannerModSettlementResidentRole {
+public enum SettlementResidentRole {
VILLAGER,
CONTROLLED_WORKER,
GOVERNOR_RECRUIT;
- public static BannerModSettlementResidentRole fromTagName(String name) {
+ public static SettlementResidentRole fromTagName(String name) {
if (name == null || name.isBlank()) {
return VILLAGER;
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentRoleProfile.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentRoleProfile.java
similarity index 52%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentRoleProfile.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementResidentRoleProfile.java
index b0daa387..232419b0 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentRoleProfile.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentRoleProfile.java
@@ -2,11 +2,11 @@
import net.minecraft.nbt.CompoundTag;
-public record BannerModSettlementResidentRoleProfile(
- BannerModSettlementResidentRole role,
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed,
- BannerModSettlementResidentMode residentMode,
- BannerModSettlementResidentAssignmentState assignmentState,
+public record SettlementResidentRoleProfile(
+ SettlementResidentRole role,
+ SettlementResidentRuntimeRoleState runtimeRoleState,
+ SettlementResidentMode residentMode,
+ SettlementResidentAssignmentState assignmentState,
String profileId,
String goalDomainId,
boolean prefersLocalBuilding
@@ -14,7 +14,7 @@ public record BannerModSettlementResidentRoleProfile(
public CompoundTag toTag() {
CompoundTag tag = new CompoundTag();
tag.putString("Role", this.role.name());
- tag.putString("RuntimeRoleSeed", this.runtimeRoleSeed.name());
+ tag.putString("RuntimeRoleSeed", this.runtimeRoleState.name());
tag.putString("ResidentMode", this.residentMode.name());
tag.putString("AssignmentState", this.assignmentState.name());
tag.putString("ProfileId", this.profileId);
@@ -23,66 +23,66 @@ public CompoundTag toTag() {
return tag;
}
- public static BannerModSettlementResidentRoleProfile fromTag(CompoundTag tag) {
- return new BannerModSettlementResidentRoleProfile(
- BannerModSettlementResidentRole.fromTagName(tag.getString("Role")),
- BannerModSettlementResidentRuntimeRoleSeed.fromTagName(tag.getString("RuntimeRoleSeed")),
- BannerModSettlementResidentMode.fromTagName(tag.getString("ResidentMode")),
- BannerModSettlementResidentAssignmentState.fromTagName(tag.getString("AssignmentState")),
+ public static SettlementResidentRoleProfile fromTag(CompoundTag tag) {
+ return new SettlementResidentRoleProfile(
+ SettlementResidentRole.fromTagName(tag.getString("Role")),
+ SettlementResidentRuntimeRoleState.fromTagName(tag.getString("RuntimeRoleSeed")),
+ SettlementResidentMode.fromTagName(tag.getString("ResidentMode")),
+ SettlementResidentAssignmentState.fromTagName(tag.getString("AssignmentState")),
tag.getString("ProfileId"),
tag.getString("GoalDomainId"),
tag.getBoolean("PrefersLocalBuilding")
);
}
- public static BannerModSettlementResidentRoleProfile defaultFor(BannerModSettlementResidentRole role,
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed,
- BannerModSettlementResidentMode residentMode,
- BannerModSettlementResidentAssignmentState assignmentState) {
- return switch (runtimeRoleSeed) {
- case VILLAGE_LIFE -> new BannerModSettlementResidentRoleProfile(
+ public static SettlementResidentRoleProfile defaultFor(SettlementResidentRole role,
+ SettlementResidentRuntimeRoleState runtimeRoleState,
+ SettlementResidentMode residentMode,
+ SettlementResidentAssignmentState assignmentState) {
+ return switch (runtimeRoleState) {
+ case VILLAGE_LIFE -> new SettlementResidentRoleProfile(
role,
- runtimeRoleSeed,
+ runtimeRoleState,
residentMode,
assignmentState,
"village_life",
"village",
false
);
- case GOVERNANCE -> new BannerModSettlementResidentRoleProfile(
+ case GOVERNANCE -> new SettlementResidentRoleProfile(
role,
- runtimeRoleSeed,
+ runtimeRoleState,
residentMode,
assignmentState,
"governance",
"governance",
false
);
- case LOCAL_LABOR -> new BannerModSettlementResidentRoleProfile(
+ case LOCAL_LABOR -> new SettlementResidentRoleProfile(
role,
- runtimeRoleSeed,
+ runtimeRoleState,
residentMode,
assignmentState,
- residentMode == BannerModSettlementResidentMode.PROJECTED_CONTROLLED_WORKER
+ residentMode == SettlementResidentMode.PROJECTED_CONTROLLED_WORKER
? "projected_local_labor"
: "local_labor",
"labor",
true
);
- case FLOATING_LABOR -> new BannerModSettlementResidentRoleProfile(
+ case FLOATING_LABOR -> new SettlementResidentRoleProfile(
role,
- runtimeRoleSeed,
+ runtimeRoleState,
residentMode,
assignmentState,
- residentMode == BannerModSettlementResidentMode.PROJECTED_CONTROLLED_WORKER
+ residentMode == SettlementResidentMode.PROJECTED_CONTROLLED_WORKER
? "projected_floating_labor"
: "floating_labor",
"labor",
false
);
- case ORPHANED_LABOR_ASSIGNMENT -> new BannerModSettlementResidentRoleProfile(
+ case ORPHANED_LABOR_ASSIGNMENT -> new SettlementResidentRoleProfile(
role,
- runtimeRoleSeed,
+ runtimeRoleState,
residentMode,
assignmentState,
"orphaned_labor_assignment",
diff --git a/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentRuntimeRoleState.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentRuntimeRoleState.java
new file mode 100644
index 00000000..cc90dee3
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentRuntimeRoleState.java
@@ -0,0 +1,47 @@
+package com.talhanation.bannermod.settlement;
+
+public enum SettlementResidentRuntimeRoleState {
+ VILLAGE_LIFE,
+ GOVERNANCE,
+ LOCAL_LABOR,
+ FLOATING_LABOR,
+ ORPHANED_LABOR_ASSIGNMENT;
+
+ public static SettlementResidentRuntimeRoleState fromTagName(String name) {
+ if (name == null || name.isBlank()) {
+ return VILLAGE_LIFE;
+ }
+ try {
+ return valueOf(name);
+ } catch (IllegalArgumentException ignored) {
+ return VILLAGE_LIFE;
+ }
+ }
+
+ public static SettlementResidentRuntimeRoleState defaultFor(SettlementResidentRole role,
+ SettlementResidentScheduleSeed scheduleSeed,
+ SettlementResidentMode residentMode,
+ SettlementResidentAssignmentState assignmentState) {
+ return switch (role) {
+ case GOVERNOR_RECRUIT -> GOVERNANCE;
+ case VILLAGER -> VILLAGE_LIFE;
+ case CONTROLLED_WORKER -> defaultWorkerState(scheduleSeed, residentMode, assignmentState);
+ };
+ }
+
+ private static SettlementResidentRuntimeRoleState defaultWorkerState(SettlementResidentScheduleSeed scheduleSeed,
+ SettlementResidentMode residentMode,
+ SettlementResidentAssignmentState assignmentState) {
+ if (assignmentState == SettlementResidentAssignmentState.ASSIGNED_MISSING_BUILDING) {
+ return ORPHANED_LABOR_ASSIGNMENT;
+ }
+ if (assignmentState == SettlementResidentAssignmentState.ASSIGNED_LOCAL_BUILDING
+ || scheduleSeed == SettlementResidentScheduleSeed.ASSIGNED_WORK) {
+ return LOCAL_LABOR;
+ }
+ if (residentMode == SettlementResidentMode.PROJECTED_CONTROLLED_WORKER) {
+ return FLOATING_LABOR;
+ }
+ return FLOATING_LABOR;
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentSchedulePolicy.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentSchedulePolicy.java
new file mode 100644
index 00000000..d6557e62
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentSchedulePolicy.java
@@ -0,0 +1,83 @@
+package com.talhanation.bannermod.settlement;
+
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.Tag;
+
+public record SettlementResidentSchedulePolicy(
+ SettlementResidentSchedulePolicySeed policySeed,
+ SettlementResidentScheduleSeed scheduleSeed,
+ SettlementResidentScheduleWindowSeed scheduleWindowSeed,
+ String goalDomainId,
+ boolean prefersLocalBuilding
+) {
+ public CompoundTag toTag() {
+ CompoundTag tag = new CompoundTag();
+ tag.putString("PolicySeed", this.policySeed.name());
+ tag.putString("ScheduleSeed", this.scheduleSeed.name());
+ tag.putString("ScheduleWindowSeed", this.scheduleWindowSeed.name());
+ tag.putString("GoalDomainId", this.goalDomainId);
+ tag.putBoolean("PrefersLocalBuilding", this.prefersLocalBuilding);
+ return tag;
+ }
+
+ public static SettlementResidentSchedulePolicy fromTag(CompoundTag tag) {
+ SettlementResidentSchedulePolicySeed policySeed = tag.contains("PolicySeed", Tag.TAG_STRING)
+ ? SettlementResidentSchedulePolicySeed.fromTagName(tag.getString("PolicySeed"))
+ : SettlementResidentSchedulePolicySeed.VILLAGE_LIFE_FLEX;
+ SettlementResidentScheduleSeed scheduleSeed = tag.contains("ScheduleSeed", Tag.TAG_STRING)
+ ? scheduleSeedFromTagName(tag.getString("ScheduleSeed"))
+ : SettlementResidentScheduleSeed.SETTLEMENT_IDLE;
+ SettlementResidentScheduleWindowSeed scheduleWindowSeed = tag.contains("ScheduleWindowSeed", Tag.TAG_STRING)
+ ? SettlementResidentScheduleWindowSeed.fromTagName(tag.getString("ScheduleWindowSeed"))
+ : SettlementResidentScheduleWindowSeed.DAYLIGHT_FLEX;
+ String goalDomainId = tag.contains("GoalDomainId", Tag.TAG_STRING)
+ ? tag.getString("GoalDomainId")
+ : "village";
+ return new SettlementResidentSchedulePolicy(
+ policySeed,
+ scheduleSeed,
+ scheduleWindowSeed,
+ goalDomainId,
+ tag.getBoolean("PrefersLocalBuilding")
+ );
+ }
+
+ public static SettlementResidentSchedulePolicy defaultFor(SettlementResidentScheduleSeed scheduleSeed,
+ SettlementResidentScheduleWindowSeed scheduleWindowSeed,
+ SettlementResidentRuntimeRoleState runtimeRoleState,
+ SettlementResidentRoleProfile roleProfile) {
+ return new SettlementResidentSchedulePolicy(
+ defaultPolicySeed(scheduleSeed, scheduleWindowSeed, runtimeRoleState),
+ scheduleSeed,
+ scheduleWindowSeed,
+ roleProfile.goalDomainId(),
+ roleProfile.prefersLocalBuilding()
+ );
+ }
+
+ private static SettlementResidentSchedulePolicySeed defaultPolicySeed(SettlementResidentScheduleSeed scheduleSeed,
+ SettlementResidentScheduleWindowSeed scheduleWindowSeed,
+ SettlementResidentRuntimeRoleState runtimeRoleState) {
+ return switch (runtimeRoleState) {
+ case GOVERNANCE -> SettlementResidentSchedulePolicySeed.GOVERNANCE_CIVIC;
+ case LOCAL_LABOR -> SettlementResidentSchedulePolicySeed.LOCAL_LABOR_DAY;
+ case FLOATING_LABOR -> scheduleWindowSeed == SettlementResidentScheduleWindowSeed.LABOR_DAY
+ || scheduleSeed == SettlementResidentScheduleSeed.ASSIGNED_WORK
+ ? SettlementResidentSchedulePolicySeed.LOCAL_LABOR_DAY
+ : SettlementResidentSchedulePolicySeed.FLOATING_LABOR_FLEX;
+ case ORPHANED_LABOR_ASSIGNMENT -> SettlementResidentSchedulePolicySeed.ORPHANED_LABOR_DAY;
+ case VILLAGE_LIFE -> scheduleWindowSeed == SettlementResidentScheduleWindowSeed.CIVIC_DAY
+ || scheduleSeed == SettlementResidentScheduleSeed.GOVERNING
+ ? SettlementResidentSchedulePolicySeed.GOVERNANCE_CIVIC
+ : SettlementResidentSchedulePolicySeed.VILLAGE_LIFE_FLEX;
+ };
+ }
+
+ private static SettlementResidentScheduleSeed scheduleSeedFromTagName(String name) {
+ try {
+ return SettlementResidentScheduleSeed.valueOf(name);
+ } catch (IllegalArgumentException exception) {
+ return SettlementResidentScheduleSeed.SETTLEMENT_IDLE;
+ }
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentSchedulePolicySeed.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentSchedulePolicySeed.java
similarity index 55%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentSchedulePolicySeed.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementResidentSchedulePolicySeed.java
index 843cc068..b27ce462 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentSchedulePolicySeed.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentSchedulePolicySeed.java
@@ -1,15 +1,15 @@
package com.talhanation.bannermod.settlement;
-public enum BannerModSettlementResidentSchedulePolicySeed {
+public enum SettlementResidentSchedulePolicySeed {
VILLAGE_LIFE_FLEX,
GOVERNANCE_CIVIC,
LOCAL_LABOR_DAY,
FLOATING_LABOR_FLEX,
ORPHANED_LABOR_DAY;
- public static BannerModSettlementResidentSchedulePolicySeed fromTagName(String name) {
+ public static SettlementResidentSchedulePolicySeed fromTagName(String name) {
try {
- return BannerModSettlementResidentSchedulePolicySeed.valueOf(name);
+ return SettlementResidentSchedulePolicySeed.valueOf(name);
} catch (IllegalArgumentException exception) {
return VILLAGE_LIFE_FLEX;
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentScheduleSeed.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentScheduleSeed.java
similarity index 75%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentScheduleSeed.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementResidentScheduleSeed.java
index 989ab9bf..e77388d4 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentScheduleSeed.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentScheduleSeed.java
@@ -3,12 +3,12 @@
import javax.annotation.Nullable;
import java.util.UUID;
-public enum BannerModSettlementResidentScheduleSeed {
+public enum SettlementResidentScheduleSeed {
SETTLEMENT_IDLE,
ASSIGNED_WORK,
GOVERNING;
- public static BannerModSettlementResidentScheduleSeed defaultFor(BannerModSettlementResidentRole role,
+ public static SettlementResidentScheduleSeed defaultFor(SettlementResidentRole role,
@Nullable UUID boundWorkAreaUuid) {
return switch (role) {
case VILLAGER -> SETTLEMENT_IDLE;
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentScheduleWindowSeed.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentScheduleWindowSeed.java
similarity index 57%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentScheduleWindowSeed.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementResidentScheduleWindowSeed.java
index a99a8b23..36ca5930 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentScheduleWindowSeed.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentScheduleWindowSeed.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.settlement;
-public enum BannerModSettlementResidentScheduleWindowSeed {
+public enum SettlementResidentScheduleWindowSeed {
DAYLIGHT_FLEX(1000, 11000, 12000, 23999),
LABOR_DAY(1000, 9000, 12000, 23999),
CIVIC_DAY(500, 11000, 12000, 23999);
@@ -10,7 +10,7 @@ public enum BannerModSettlementResidentScheduleWindowSeed {
private final int restStartTick;
private final int restEndTick;
- BannerModSettlementResidentScheduleWindowSeed(int activeStartTick,
+ SettlementResidentScheduleWindowSeed(int activeStartTick,
int activeEndTick,
int restStartTick,
int restEndTick) {
@@ -36,23 +36,23 @@ public int restEndTick() {
return this.restEndTick;
}
- public static BannerModSettlementResidentScheduleWindowSeed defaultFor(BannerModSettlementResidentScheduleSeed scheduleSeed,
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed) {
- if (runtimeRoleSeed == BannerModSettlementResidentRuntimeRoleSeed.GOVERNANCE
- || scheduleSeed == BannerModSettlementResidentScheduleSeed.GOVERNING) {
+ public static SettlementResidentScheduleWindowSeed defaultFor(SettlementResidentScheduleSeed scheduleSeed,
+ SettlementResidentRuntimeRoleState runtimeRoleState) {
+ if (runtimeRoleState == SettlementResidentRuntimeRoleState.GOVERNANCE
+ || scheduleSeed == SettlementResidentScheduleSeed.GOVERNING) {
return CIVIC_DAY;
}
- if (runtimeRoleSeed == BannerModSettlementResidentRuntimeRoleSeed.LOCAL_LABOR
- || runtimeRoleSeed == BannerModSettlementResidentRuntimeRoleSeed.ORPHANED_LABOR_ASSIGNMENT
- || scheduleSeed == BannerModSettlementResidentScheduleSeed.ASSIGNED_WORK) {
+ if (runtimeRoleState == SettlementResidentRuntimeRoleState.LOCAL_LABOR
+ || runtimeRoleState == SettlementResidentRuntimeRoleState.ORPHANED_LABOR_ASSIGNMENT
+ || scheduleSeed == SettlementResidentScheduleSeed.ASSIGNED_WORK) {
return LABOR_DAY;
}
return DAYLIGHT_FLEX;
}
- public static BannerModSettlementResidentScheduleWindowSeed fromTagName(String name) {
+ public static SettlementResidentScheduleWindowSeed fromTagName(String name) {
try {
- return BannerModSettlementResidentScheduleWindowSeed.valueOf(name);
+ return SettlementResidentScheduleWindowSeed.valueOf(name);
} catch (IllegalArgumentException exception) {
return DAYLIGHT_FLEX;
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentServiceContract.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentServiceContract.java
similarity index 51%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentServiceContract.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementResidentServiceContract.java
index bc40c2eb..d2bb26bd 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementResidentServiceContract.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentServiceContract.java
@@ -6,8 +6,8 @@
import javax.annotation.Nullable;
import java.util.UUID;
-public record BannerModSettlementResidentServiceContract(
- BannerModSettlementServiceActorState actorState,
+public record SettlementResidentServiceContract(
+ SettlementServiceActorState actorState,
@Nullable UUID serviceBuildingUuid,
@Nullable String serviceBuildingTypeId
) {
@@ -23,39 +23,39 @@ public CompoundTag toTag() {
return tag;
}
- public static BannerModSettlementResidentServiceContract fromTag(CompoundTag tag) {
- BannerModSettlementServiceActorState actorState = tag.contains("ActorState", Tag.TAG_STRING)
- ? BannerModSettlementServiceActorState.fromTagName(tag.getString("ActorState"))
- : BannerModSettlementServiceActorState.NOT_SERVICE_ACTOR;
+ public static SettlementResidentServiceContract fromTag(CompoundTag tag) {
+ SettlementServiceActorState actorState = tag.contains("ActorState", Tag.TAG_STRING)
+ ? SettlementServiceActorState.fromTagName(tag.getString("ActorState"))
+ : SettlementServiceActorState.NOT_SERVICE_ACTOR;
UUID serviceBuildingUuid = tag.hasUUID("ServiceBuildingUuid") ? tag.getUUID("ServiceBuildingUuid") : null;
String serviceBuildingTypeId = tag.contains("ServiceBuildingTypeId", Tag.TAG_STRING)
? tag.getString("ServiceBuildingTypeId")
: null;
- return new BannerModSettlementResidentServiceContract(actorState, serviceBuildingUuid, serviceBuildingTypeId);
+ return new SettlementResidentServiceContract(actorState, serviceBuildingUuid, serviceBuildingTypeId);
}
- public static BannerModSettlementResidentServiceContract defaultFor(BannerModSettlementResidentRole role,
- BannerModSettlementResidentMode residentMode,
- BannerModSettlementResidentAssignmentState assignmentState,
+ public static SettlementResidentServiceContract defaultFor(SettlementResidentRole role,
+ SettlementResidentMode residentMode,
+ SettlementResidentAssignmentState assignmentState,
@Nullable UUID boundWorkAreaUuid,
@Nullable String serviceBuildingTypeId) {
- if (role != BannerModSettlementResidentRole.CONTROLLED_WORKER
- || residentMode != BannerModSettlementResidentMode.PROJECTED_CONTROLLED_WORKER) {
+ if (role != SettlementResidentRole.CONTROLLED_WORKER
+ || residentMode != SettlementResidentMode.PROJECTED_CONTROLLED_WORKER) {
return notServiceActor();
}
return switch (assignmentState) {
- case ASSIGNED_LOCAL_BUILDING -> new BannerModSettlementResidentServiceContract(
- BannerModSettlementServiceActorState.LOCAL_BUILDING_SERVICE,
+ case ASSIGNED_LOCAL_BUILDING -> new SettlementResidentServiceContract(
+ SettlementServiceActorState.LOCAL_BUILDING_SERVICE,
boundWorkAreaUuid,
serviceBuildingTypeId
);
- case ASSIGNED_MISSING_BUILDING -> new BannerModSettlementResidentServiceContract(
- BannerModSettlementServiceActorState.ORPHANED_SERVICE,
+ case ASSIGNED_MISSING_BUILDING -> new SettlementResidentServiceContract(
+ SettlementServiceActorState.ORPHANED_SERVICE,
boundWorkAreaUuid,
null
);
- case UNASSIGNED -> new BannerModSettlementResidentServiceContract(
- BannerModSettlementServiceActorState.FLOATING_SERVICE,
+ case UNASSIGNED -> new SettlementResidentServiceContract(
+ SettlementServiceActorState.FLOATING_SERVICE,
null,
null
);
@@ -63,7 +63,7 @@ public static BannerModSettlementResidentServiceContract defaultFor(BannerModSet
};
}
- public static BannerModSettlementResidentServiceContract notServiceActor() {
- return new BannerModSettlementResidentServiceContract(BannerModSettlementServiceActorState.NOT_SERVICE_ACTOR, null, null);
+ public static SettlementResidentServiceContract notServiceActor() {
+ return new SettlementResidentServiceContract(SettlementServiceActorState.NOT_SERVICE_ACTOR, null, null);
}
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentStaffingService.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentStaffingService.java
new file mode 100644
index 00000000..ca24648b
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementResidentStaffingService.java
@@ -0,0 +1,36 @@
+package com.talhanation.bannermod.settlement;
+
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+final class SettlementResidentStaffingService {
+
+ private SettlementResidentStaffingService() {
+ }
+
+ static StaffingResult apply(List residents,
+ List buildings,
+ SettlementMarketState marketState,
+ Set localBuildingUuids) {
+ List staffedResidents = SettlementSnapshotRuntime.applyResidentAssignmentSemantics(
+ residents,
+ localBuildingUuids
+ );
+ staffedResidents = SettlementSnapshotRuntime.applyResidentServiceContracts(staffedResidents, buildings);
+ staffedResidents = SettlementSnapshotRuntime.applyResidentJobDefinitions(staffedResidents, buildings);
+ List staffedBuildings = SettlementSnapshotRuntime.applyAssignedResidents(buildings, staffedResidents);
+ SettlementMarketState staffedMarketState = SettlementSnapshotRuntime.applySellerDispatchSeed(
+ marketState,
+ staffedResidents,
+ staffedBuildings
+ );
+ staffedResidents = SettlementSnapshotRuntime.applyResidentJobTargetSelectionStates(staffedResidents, staffedMarketState);
+ return new StaffingResult(staffedResidents, staffedBuildings, staffedMarketState);
+ }
+
+ record StaffingResult(List residents,
+ List buildings,
+ SettlementMarketState marketState) {
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementSellerDispatchRecord.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementSellerDispatchRecord.java
similarity index 66%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementSellerDispatchRecord.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementSellerDispatchRecord.java
index 7cc6fc67..64bfdef2 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementSellerDispatchRecord.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementSellerDispatchRecord.java
@@ -6,11 +6,11 @@
import javax.annotation.Nullable;
import java.util.UUID;
-public record BannerModSettlementSellerDispatchRecord(
+public record SettlementSellerDispatchRecord(
UUID residentUuid,
UUID marketUuid,
@Nullable String marketName,
- BannerModSettlementSellerDispatchState dispatchState
+ SettlementSellerDispatchState dispatchState
) {
public CompoundTag toTag() {
CompoundTag tag = new CompoundTag();
@@ -23,22 +23,22 @@ public CompoundTag toTag() {
return tag;
}
- public static BannerModSettlementSellerDispatchRecord fromTag(CompoundTag tag) {
- return new BannerModSettlementSellerDispatchRecord(
+ public static SettlementSellerDispatchRecord fromTag(CompoundTag tag) {
+ return new SettlementSellerDispatchRecord(
tag.getUUID("ResidentUuid"),
tag.getUUID("MarketUuid"),
tag.contains("MarketName", Tag.TAG_STRING) ? tag.getString("MarketName") : null,
tag.contains("DispatchState", Tag.TAG_STRING)
? dispatchStateFromTagName(tag.getString("DispatchState"))
- : BannerModSettlementSellerDispatchState.READY
+ : SettlementSellerDispatchState.READY
);
}
- private static BannerModSettlementSellerDispatchState dispatchStateFromTagName(String name) {
+ private static SettlementSellerDispatchState dispatchStateFromTagName(String name) {
try {
- return BannerModSettlementSellerDispatchState.valueOf(name);
+ return SettlementSellerDispatchState.valueOf(name);
} catch (IllegalArgumentException exception) {
- return BannerModSettlementSellerDispatchState.READY;
+ return SettlementSellerDispatchState.READY;
}
}
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementSellerDispatchState.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementSellerDispatchState.java
similarity index 59%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementSellerDispatchState.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementSellerDispatchState.java
index c3d59ab1..44c6c051 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementSellerDispatchState.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementSellerDispatchState.java
@@ -1,6 +1,6 @@
package com.talhanation.bannermod.settlement;
-public enum BannerModSettlementSellerDispatchState {
+public enum SettlementSellerDispatchState {
READY,
MARKET_CLOSED
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/SettlementService.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementService.java
new file mode 100644
index 00000000..64f9c95f
--- /dev/null
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementService.java
@@ -0,0 +1,74 @@
+package com.talhanation.bannermod.settlement;
+
+import com.talhanation.bannermod.entity.civilian.AbstractWorkerEntity;
+import com.talhanation.bannermod.entity.civilian.workarea.AbstractWorkAreaEntity;
+import com.talhanation.bannermod.governance.BannerModGovernorManager;
+import com.talhanation.bannermod.persistence.military.RecruitsClaim;
+import com.talhanation.bannermod.persistence.military.RecruitsClaimManager;
+import com.talhanation.bannermod.settlement.building.ValidatedBuildingRecord;
+import com.talhanation.bannermod.settlement.runtime.SettlementClaimBindingService;
+import net.minecraft.core.BlockPos;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.phys.AABB;
+
+import javax.annotation.Nullable;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+public final class SettlementService {
+ private SettlementService() {
+ }
+
+ public static void refreshAllClaims(ServerLevel level,
+ RecruitsClaimManager claimManager,
+ SettlementManager settlementManager,
+ BannerModGovernorManager governorManager) {
+ SettlementClaimBindingService.refreshAllClaims(level, claimManager, settlementManager, governorManager);
+ }
+
+ public static SettlementClaimBindingService.BatchResult refreshClaimsBatch(ServerLevel level,
+ RecruitsClaimManager claimManager,
+ SettlementManager settlementManager,
+ BannerModGovernorManager governorManager,
+ int startIndex,
+ int maxClaims) {
+ return SettlementClaimBindingService.refreshClaimsBatch(level, claimManager, settlementManager, governorManager, startIndex, maxClaims);
+ }
+
+ public static void refreshClaimAt(ServerLevel level,
+ RecruitsClaimManager claimManager,
+ SettlementManager settlementManager,
+ BannerModGovernorManager governorManager,
+ BlockPos pos) {
+ SettlementClaimBindingService.refreshClaimAt(level, claimManager, settlementManager, governorManager, pos);
+ }
+
+ public static void refreshClaim(ServerLevel level,
+ RecruitsClaimManager claimManager,
+ SettlementManager settlementManager,
+ @Nullable BannerModGovernorManager governorManager,
+ @Nullable RecruitsClaim claim) {
+ SettlementClaimBindingService.refreshClaim(level, claimManager, settlementManager, governorManager, claim);
+ }
+
+ public static SettlementSnapshot buildSnapshot(ServerLevel level,
+ RecruitsClaim claim,
+ @Nullable BannerModGovernorManager governorManager) {
+ return SettlementSnapshotBuilder.buildSnapshot(level, claim, governorManager);
+ }
+
+ public static List workersInClaim(ServerLevel level, RecruitsClaim claim) {
+ return SettlementSnapshotRuntime.workersInClaim(level, claim);
+ }
+
+ public static Map buildCanonicalWorkAreaBindings(Collection validatedBuildings,
+ List workAreas) {
+ return SettlementSnapshotRuntime.buildCanonicalWorkAreaBindings(validatedBuildings, workAreas);
+ }
+
+ public static AABB claimBounds(ServerLevel level, RecruitsClaim claim) {
+ return SettlementSnapshotRuntime.claimBounds(level, claim);
+ }
+}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementServiceActorState.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementServiceActorState.java
similarity index 74%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementServiceActorState.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementServiceActorState.java
index 34083ebb..096eca6c 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementServiceActorState.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementServiceActorState.java
@@ -1,12 +1,12 @@
package com.talhanation.bannermod.settlement;
-public enum BannerModSettlementServiceActorState {
+public enum SettlementServiceActorState {
NOT_SERVICE_ACTOR,
LOCAL_BUILDING_SERVICE,
FLOATING_SERVICE,
ORPHANED_SERVICE;
- public static BannerModSettlementServiceActorState fromTagName(String name) {
+ public static SettlementServiceActorState fromTagName(String name) {
if (name == null || name.isBlank()) {
return NOT_SERVICE_ACTOR;
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementSnapshot.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementSnapshot.java
similarity index 52%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementSnapshot.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementSnapshot.java
index 08fa9ce1..219a1ed3 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementSnapshot.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementSnapshot.java
@@ -10,7 +10,7 @@
import java.util.List;
import java.util.UUID;
-public record BannerModSettlementSnapshot(
+public record SettlementSnapshot(
UUID claimUuid,
int anchorChunkX,
int anchorChunkZ,
@@ -22,28 +22,28 @@ public record BannerModSettlementSnapshot(
int assignedResidentCount,
int unassignedWorkerCount,
int missingWorkAreaAssignmentCount,
- BannerModSettlementStockpileSummary stockpileSummary,
- BannerModSettlementMarketState marketState,
- BannerModSettlementDesiredGoodsSeed desiredGoodsSeed,
- BannerModSettlementProjectCandidateSeed projectCandidateSeed,
- BannerModSettlementTradeRouteHandoffSeed tradeRouteHandoffSeed,
- BannerModSettlementSupplySignalState supplySignalState,
- List residents,
- List buildings
+ SettlementStockpileSummary stockpileSummary,
+ SettlementMarketState marketState,
+ SettlementDesiredGoodsSnapshot desiredGoodsSnapshot,
+ SettlementProjectCandidateSnapshot projectCandidateSnapshot,
+ SettlementTradeRouteHandoffSnapshot tradeRouteHandoffSnapshot,
+ SettlementSupplySignalState supplySignalState,
+ List residents,
+ List buildings
) {
- public BannerModSettlementSnapshot {
+ public SettlementSnapshot {
residentCapacity = Math.max(0, residentCapacity);
workplaceCapacity = Math.max(0, workplaceCapacity);
assignedWorkerCount = Math.max(0, assignedWorkerCount);
assignedResidentCount = Math.max(0, assignedResidentCount);
unassignedWorkerCount = Math.max(0, unassignedWorkerCount);
missingWorkAreaAssignmentCount = Math.max(0, missingWorkAreaAssignmentCount);
- stockpileSummary = stockpileSummary == null ? BannerModSettlementStockpileSummary.empty() : stockpileSummary;
- marketState = marketState == null ? BannerModSettlementMarketState.empty() : marketState;
- desiredGoodsSeed = desiredGoodsSeed == null ? BannerModSettlementDesiredGoodsSeed.empty() : desiredGoodsSeed;
- projectCandidateSeed = projectCandidateSeed == null ? BannerModSettlementProjectCandidateSeed.empty() : projectCandidateSeed;
- tradeRouteHandoffSeed = tradeRouteHandoffSeed == null ? BannerModSettlementTradeRouteHandoffSeed.empty() : tradeRouteHandoffSeed;
- supplySignalState = supplySignalState == null ? BannerModSettlementSupplySignalState.empty() : supplySignalState;
+ stockpileSummary = stockpileSummary == null ? SettlementStockpileSummary.empty() : stockpileSummary;
+ marketState = marketState == null ? SettlementMarketState.empty() : marketState;
+ desiredGoodsSnapshot = desiredGoodsSnapshot == null ? SettlementDesiredGoodsSnapshot.empty() : desiredGoodsSnapshot;
+ projectCandidateSnapshot = projectCandidateSnapshot == null ? SettlementProjectCandidateSnapshot.empty() : projectCandidateSnapshot;
+ tradeRouteHandoffSnapshot = tradeRouteHandoffSnapshot == null ? SettlementTradeRouteHandoffSnapshot.empty() : tradeRouteHandoffSnapshot;
+ supplySignalState = supplySignalState == null ? SettlementSupplySignalState.empty() : supplySignalState;
residents = List.copyOf(residents == null ? List.of() : residents);
buildings = List.copyOf(buildings == null ? List.of() : buildings);
}
@@ -69,26 +69,26 @@ public CompoundTag toTag() {
tag.putInt("MissingWorkAreaAssignmentCount", this.missingWorkAreaAssignmentCount);
tag.put("StockpileSummary", this.stockpileSummary.toTag());
tag.put("MarketState", this.marketState.toTag());
- tag.put("DesiredGoodsSeed", this.desiredGoodsSeed.toTag());
- tag.put("ProjectCandidateSeed", this.projectCandidateSeed.toTag());
- tag.put("TradeRouteHandoffSeed", this.tradeRouteHandoffSeed.toTag());
+ tag.put("DesiredGoodsSeed", this.desiredGoodsSnapshot.toTag());
+ tag.put("ProjectCandidateSeed", this.projectCandidateSnapshot.toTag());
+ tag.put("TradeRouteHandoffSeed", this.tradeRouteHandoffSnapshot.toTag());
tag.put("SupplySignalState", this.supplySignalState.toTag());
ListTag residentList = new ListTag();
- for (BannerModSettlementResidentRecord resident : this.residents) {
+ for (SettlementResidentRecord resident : this.residents) {
residentList.add(resident.toTag());
}
tag.put("Residents", residentList);
ListTag buildingList = new ListTag();
- for (BannerModSettlementBuildingRecord building : this.buildings) {
+ for (SettlementBuildingRecord building : this.buildings) {
buildingList.add(building.toTag());
}
tag.put("Buildings", buildingList);
return tag;
}
- public static BannerModSettlementSnapshot fromTag(CompoundTag tag) {
+ public static SettlementSnapshot fromTag(CompoundTag tag) {
String settlementFactionId = tag.contains("SettlementFactionId", Tag.TAG_STRING) ? tag.getString("SettlementFactionId") : null;
- return new BannerModSettlementSnapshot(
+ return new SettlementSnapshot(
tag.getUUID("ClaimUuid"),
tag.getInt("AnchorChunkX"),
tag.getInt("AnchorChunkZ"),
@@ -101,44 +101,44 @@ public static BannerModSettlementSnapshot fromTag(CompoundTag tag) {
tag.getInt("UnassignedWorkerCount"),
tag.getInt("MissingWorkAreaAssignmentCount"),
tag.contains("StockpileSummary", Tag.TAG_COMPOUND)
- ? BannerModSettlementStockpileSummary.fromTag(tag.getCompound("StockpileSummary"))
- : BannerModSettlementStockpileSummary.empty(),
+ ? SettlementStockpileSummary.fromTag(tag.getCompound("StockpileSummary"))
+ : SettlementStockpileSummary.empty(),
tag.contains("MarketState", Tag.TAG_COMPOUND)
- ? BannerModSettlementMarketState.fromTag(tag.getCompound("MarketState"))
- : BannerModSettlementMarketState.empty(),
+ ? SettlementMarketState.fromTag(tag.getCompound("MarketState"))
+ : SettlementMarketState.empty(),
tag.contains("DesiredGoodsSeed", Tag.TAG_COMPOUND)
- ? BannerModSettlementDesiredGoodsSeed.fromTag(tag.getCompound("DesiredGoodsSeed"))
- : BannerModSettlementDesiredGoodsSeed.empty(),
+ ? SettlementDesiredGoodsSnapshot.fromTag(tag.getCompound("DesiredGoodsSeed"))
+ : SettlementDesiredGoodsSnapshot.empty(),
tag.contains("ProjectCandidateSeed", Tag.TAG_COMPOUND)
- ? BannerModSettlementProjectCandidateSeed.fromTag(tag.getCompound("ProjectCandidateSeed"))
- : BannerModSettlementProjectCandidateSeed.empty(),
+ ? SettlementProjectCandidateSnapshot.fromTag(tag.getCompound("ProjectCandidateSeed"))
+ : SettlementProjectCandidateSnapshot.empty(),
tag.contains("TradeRouteHandoffSeed", Tag.TAG_COMPOUND)
- ? BannerModSettlementTradeRouteHandoffSeed.fromTag(tag.getCompound("TradeRouteHandoffSeed"))
- : BannerModSettlementTradeRouteHandoffSeed.empty(),
+ ? SettlementTradeRouteHandoffSnapshot.fromTag(tag.getCompound("TradeRouteHandoffSeed"))
+ : SettlementTradeRouteHandoffSnapshot.empty(),
tag.contains("SupplySignalState", Tag.TAG_COMPOUND)
- ? BannerModSettlementSupplySignalState.fromTag(tag.getCompound("SupplySignalState"))
- : BannerModSettlementSupplySignalState.empty(),
+ ? SettlementSupplySignalState.fromTag(tag.getCompound("SupplySignalState"))
+ : SettlementSupplySignalState.empty(),
readResidents(tag.getList("Residents", Tag.TAG_COMPOUND)),
readBuildings(tag.getList("Buildings", Tag.TAG_COMPOUND))
);
}
- public static BannerModSettlementSnapshot create(UUID claimUuid, ChunkPos anchorChunk, @Nullable String settlementFactionId) {
- return new BannerModSettlementSnapshot(claimUuid, anchorChunk.x, anchorChunk.z, settlementFactionId, 0L, 0, 0, 0, 0, 0, 0, BannerModSettlementStockpileSummary.empty(), BannerModSettlementMarketState.empty(), BannerModSettlementDesiredGoodsSeed.empty(), BannerModSettlementProjectCandidateSeed.empty(), BannerModSettlementTradeRouteHandoffSeed.empty(), BannerModSettlementSupplySignalState.empty(), List.of(), List.of());
+ public static SettlementSnapshot create(UUID claimUuid, ChunkPos anchorChunk, @Nullable String settlementFactionId) {
+ return new SettlementSnapshot(claimUuid, anchorChunk.x, anchorChunk.z, settlementFactionId, 0L, 0, 0, 0, 0, 0, 0, SettlementStockpileSummary.empty(), SettlementMarketState.empty(), SettlementDesiredGoodsSnapshot.empty(), SettlementProjectCandidateSnapshot.empty(), SettlementTradeRouteHandoffSnapshot.empty(), SettlementSupplySignalState.empty(), List.of(), List.of());
}
- private static List readResidents(ListTag list) {
- List residents = new ArrayList<>();
+ private static List readResidents(ListTag list) {
+ List residents = new ArrayList<>();
for (Tag entry : list) {
- residents.add(BannerModSettlementResidentRecord.fromTag((CompoundTag) entry));
+ residents.add(SettlementResidentRecord.fromTag((CompoundTag) entry));
}
return residents;
}
- private static List readBuildings(ListTag list) {
- List buildings = new ArrayList<>();
+ private static List readBuildings(ListTag list) {
+ List buildings = new ArrayList<>();
for (Tag entry : list) {
- buildings.add(BannerModSettlementBuildingRecord.fromTag((CompoundTag) entry));
+ buildings.add(SettlementBuildingRecord.fromTag((CompoundTag) entry));
}
return buildings;
}
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementSnapshotBuilder.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementSnapshotBuilder.java
similarity index 62%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementSnapshotBuilder.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementSnapshotBuilder.java
index 50c57514..b0a6bd1f 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementSnapshotBuilder.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementSnapshotBuilder.java
@@ -19,48 +19,51 @@
import java.util.Set;
import java.util.UUID;
-final class BannerModSettlementSnapshotBuilder {
+final class SettlementSnapshotBuilder {
- private BannerModSettlementSnapshotBuilder() {
+ private SettlementSnapshotBuilder() {
}
- static BannerModSettlementSnapshot buildSnapshot(ServerLevel level,
+ static SettlementSnapshot buildSnapshot(ServerLevel level,
RecruitsClaim claim,
@Nullable BannerModGovernorManager governorManager) {
- ChunkPos anchorChunk = BannerModSettlementService.resolveAnchorChunk(claim);
+ ChunkPos anchorChunk = SettlementSnapshotRuntime.resolveAnchorChunk(claim);
BannerModGovernorSnapshot governorSnapshot = governorManager == null ? null : governorManager.getSnapshot(claim.getUUID());
- String settlementFactionId = claim.getOwnerPoliticalEntityId() != null
- ? claim.getOwnerPoliticalEntityId().toString()
- : governorSnapshot == null ? null : governorSnapshot.settlementFactionId();
+ String settlementFactionId = null;
+ if (claim.getOwnerPoliticalEntityId() != null) {
+ settlementFactionId = claim.getOwnerPoliticalEntityId().toString();
+ } else if (governorSnapshot != null) {
+ settlementFactionId = governorSnapshot.settlementFactionId();
+ }
- List workAreas = BannerModSettlementService.collectWorkAreas(level, claim, AbstractWorkAreaEntity.class);
- SettlementRecord settlementRecord = BannerModSettlementService.settlementRecordForClaim(level, claim);
- List validatedBuildings = BannerModSettlementService.collectValidatedBuildings(level, settlementRecord);
- BannerModSettlementService.repairClaimState(level, claim, workAreas, validatedBuildings);
+ List workAreas = SettlementSnapshotRuntime.collectWorkAreas(level, claim, AbstractWorkAreaEntity.class);
+ SettlementRecord settlementRecord = SettlementSnapshotRuntime.settlementRecordForClaim(level, claim);
+ List validatedBuildings = SettlementSnapshotRuntime.collectValidatedBuildings(level, settlementRecord);
+ SettlementSnapshotRuntime.repairClaimState(level, claim, workAreas, validatedBuildings);
- List residents = BannerModSettlementService.collectResidents(level, claim, governorSnapshot, settlementFactionId);
- List buildings = BannerModSettlementService.collectBuildings(level, claim);
- BannerModSettlementMarketState marketState = BannerModSettlementService.collectMarketState(level, claim);
- List storageAreas = BannerModSettlementService.collectStorageAreas(level, claim);
- List liveSeaTradeEntrypoints = BannerModSettlementService.collectLiveSeaTradeEntrypoints(storageAreas);
- List localSeaTradeExecutions = BannerModSettlementService.collectLocalSeaTradeExecutions(level, storageAreas);
+ List residents = SettlementSnapshotRuntime.collectResidents(level, claim, governorSnapshot, settlementFactionId);
+ List buildings = SettlementSnapshotRuntime.collectBuildings(level, claim);
+ SettlementMarketState marketState = SettlementSnapshotRuntime.collectMarketState(level, claim);
+ List storageAreas = SettlementSnapshotRuntime.collectStorageAreas(level, claim);
+ List liveSeaTradeEntrypoints = SettlementSnapshotRuntime.collectLiveSeaTradeEntrypoints(storageAreas);
+ List localSeaTradeExecutions = SettlementSnapshotRuntime.collectLocalSeaTradeExecutions(level, storageAreas);
Set localBuildingUuids = new LinkedHashSet<>();
- for (BannerModSettlementBuildingRecord building : buildings) {
+ for (SettlementBuildingRecord building : buildings) {
localBuildingUuids.add(building.buildingUuid());
}
- BannerModSettlementResidentStaffingService.StaffingResult staffing = BannerModSettlementResidentStaffingService.apply(
+ SettlementResidentStaffingService.StaffingResult staffing = SettlementResidentStaffingService.apply(
residents,
buildings,
marketState,
localBuildingUuids
);
- BannerModSettlementLogisticsDerivationService.LogisticsResult logistics = BannerModSettlementLogisticsDerivationService.derive(
+ SettlementLogisticsDerivationService.LogisticsResult logistics = SettlementLogisticsDerivationService.derive(
staffing.buildings(),
staffing.residents(),
staffing.marketState(),
liveSeaTradeEntrypoints,
- BannerModSettlementService.collectLocalLogisticsRoutes(storageAreas),
+ SettlementSnapshotRuntime.collectLocalLogisticsRoutes(storageAreas),
BannerModLogisticsRuntime.service().listReservations(),
localSeaTradeExecutions,
governorSnapshot != null && governorSnapshot.governorRecruitUuid() != null,
@@ -68,7 +71,7 @@ static BannerModSettlementSnapshot buildSnapshot(ServerLevel level,
);
SnapshotCounts counts = summarizeCounts(staffing.buildings(), staffing.residents());
- return new BannerModSettlementSnapshot(
+ return new SettlementSnapshot(
claim.getUUID(),
anchorChunk.x,
anchorChunk.z,
@@ -82,30 +85,30 @@ static BannerModSettlementSnapshot buildSnapshot(ServerLevel level,
counts.missingWorkAreaAssignmentCount(),
logistics.stockpileSummary(),
staffing.marketState(),
- logistics.desiredGoodsSeed(),
- logistics.projectCandidateSeed(),
- logistics.tradeRouteHandoffSeed(),
+ logistics.desiredGoodsSnapshot(),
+ logistics.projectCandidateSnapshot(),
+ logistics.tradeRouteHandoffSnapshot(),
logistics.supplySignalState(),
staffing.residents(),
staffing.buildings()
);
}
- private static SnapshotCounts summarizeCounts(List buildings,
- List residents) {
+ private static SnapshotCounts summarizeCounts(List buildings,
+ List residents) {
int residentCapacity = 0;
int workplaceCapacity = 0;
int assignedWorkerCount = 0;
int assignedResidentCount = 0;
int unassignedWorkerCount = 0;
int missingWorkAreaAssignmentCount = 0;
- for (BannerModSettlementBuildingRecord building : buildings) {
+ for (SettlementBuildingRecord building : buildings) {
residentCapacity += Math.max(0, building.residentCapacity());
workplaceCapacity += Math.max(0, building.workplaceSlots());
assignedWorkerCount += Math.max(0, building.assignedWorkerCount());
}
- for (BannerModSettlementResidentRecord resident : residents) {
- if (resident.role() != BannerModSettlementResidentRole.CONTROLLED_WORKER) {
+ for (SettlementResidentRecord resident : residents) {
+ if (resident.role() != SettlementResidentRole.CONTROLLED_WORKER) {
continue;
}
switch (resident.assignmentState()) {
diff --git a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementService.java b/src/main/java/com/talhanation/bannermod/settlement/SettlementSnapshotRuntime.java
similarity index 62%
rename from src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementService.java
rename to src/main/java/com/talhanation/bannermod/settlement/SettlementSnapshotRuntime.java
index 969f57d8..e82bb3d7 100644
--- a/src/main/java/com/talhanation/bannermod/settlement/BannerModSettlementService.java
+++ b/src/main/java/com/talhanation/bannermod/settlement/SettlementSnapshotRuntime.java
@@ -10,10 +10,9 @@
import com.talhanation.bannermod.entity.civilian.workarea.StorageArea;
import com.talhanation.bannermod.entity.civilian.workarea.WorkAreaIndex;
import com.talhanation.bannermod.settlement.runtime.SettlementClaimBindingService;
-import com.talhanation.bannermod.governance.BannerModGovernorManager;
+import com.talhanation.bannermod.settlement.runtime.SettlementSeaTradeAnalyzer;
import com.talhanation.bannermod.governance.BannerModGovernorSnapshot;
import com.talhanation.bannermod.persistence.military.RecruitsClaim;
-import com.talhanation.bannermod.persistence.military.RecruitsClaimManager;
import com.talhanation.bannermod.settlement.bootstrap.SettlementRecord;
import com.talhanation.bannermod.settlement.bootstrap.SettlementRegistryData;
import com.talhanation.bannermod.settlement.building.BuildingType;
@@ -40,7 +39,6 @@
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -51,46 +49,8 @@
import java.util.Set;
import java.util.UUID;
-public final class BannerModSettlementService {
- private BannerModSettlementService() {
- }
-
- public static void refreshAllClaims(ServerLevel level,
- RecruitsClaimManager claimManager,
- BannerModSettlementManager settlementManager,
- BannerModGovernorManager governorManager) {
- SettlementClaimBindingService.refreshAllClaims(level, claimManager, settlementManager, governorManager);
- }
-
- public static SettlementClaimBindingService.BatchResult refreshClaimsBatch(ServerLevel level,
- RecruitsClaimManager claimManager,
- BannerModSettlementManager settlementManager,
- BannerModGovernorManager governorManager,
- int startIndex,
- int maxClaims) {
- return SettlementClaimBindingService.refreshClaimsBatch(level, claimManager, settlementManager, governorManager, startIndex, maxClaims);
- }
-
- public static void refreshClaimAt(ServerLevel level,
- RecruitsClaimManager claimManager,
- BannerModSettlementManager settlementManager,
- BannerModGovernorManager governorManager,
- BlockPos pos) {
- SettlementClaimBindingService.refreshClaimAt(level, claimManager, settlementManager, governorManager, pos);
- }
-
- public static void refreshClaim(ServerLevel level,
- RecruitsClaimManager claimManager,
- BannerModSettlementManager settlementManager,
- @Nullable BannerModGovernorManager governorManager,
- @Nullable RecruitsClaim claim) {
- SettlementClaimBindingService.refreshClaim(level, claimManager, settlementManager, governorManager, claim);
- }
-
- public static BannerModSettlementSnapshot buildSnapshot(ServerLevel level,
- RecruitsClaim claim,
- @Nullable BannerModGovernorManager governorManager) {
- return BannerModSettlementSnapshotBuilder.buildSnapshot(level, claim, governorManager);
+final class SettlementSnapshotRuntime {
+ private SettlementSnapshotRuntime() {
}
static void repairClaimState(ServerLevel level,
@@ -100,55 +60,55 @@ static void repairClaimState(ServerLevel level,
SettlementClaimBindingService.repairClaimState(level, claim, workAreas, validatedBuildings);
}
- static List collectResidents(ServerLevel level,
+ static List collectResidents(ServerLevel level,
RecruitsClaim claim,
@Nullable BannerModGovernorSnapshot governorSnapshot,
@Nullable String settlementFactionId) {
- Map residents = new LinkedHashMap<>();
+ Map residents = new LinkedHashMap<>();
for (Villager villager : level.getEntitiesOfClass(Villager.class, claimBounds(level, claim), entity -> entity.isAlive() && claim.containsChunk(entity.chunkPosition()))) {
- residents.put(villager.getUUID(), new BannerModSettlementResidentRecord(
+ residents.put(villager.getUUID(), new SettlementResidentRecord(
villager.getUUID(),
- BannerModSettlementResidentRole.VILLAGER,
- BannerModSettlementResidentScheduleSeed.SETTLEMENT_IDLE,
- BannerModSettlementResidentScheduleWindowSeed.DAYLIGHT_FLEX,
- BannerModSettlementResidentRuntimeRoleSeed.VILLAGE_LIFE,
- BannerModSettlementResidentServiceContract.notServiceActor(),
- BannerModSettlementResidentJobDefinition.defaultFor(
- BannerModSettlementResidentRole.VILLAGER,
- BannerModSettlementResidentRuntimeRoleSeed.VILLAGE_LIFE,
- BannerModSettlementResidentServiceContract.notServiceActor(),
+ SettlementResidentRole.VILLAGER,
+ SettlementResidentScheduleSeed.SETTLEMENT_IDLE,
+ SettlementResidentScheduleWindowSeed.DAYLIGHT_FLEX,
+ SettlementResidentRuntimeRoleState.VILLAGE_LIFE,
+ SettlementResidentServiceContract.notServiceActor(),
+ SettlementResidentJobDefinition.defaultFor(
+ SettlementResidentRole.VILLAGER,
+ SettlementResidentRuntimeRoleState.VILLAGE_LIFE,
+ SettlementResidentServiceContract.notServiceActor(),
null
),
- BannerModSettlementResidentMode.SETTLEMENT_RESIDENT,
+ SettlementResidentMode.SETTLEMENT_RESIDENT,
null,
villager.getTeam() == null ? settlementFactionId : villager.getTeam().getName(),
null,
- BannerModSettlementResidentAssignmentState.NOT_APPLICABLE
+ SettlementResidentAssignmentState.NOT_APPLICABLE
));
}
for (AbstractWorkerEntity worker : workersInClaim(level, claim)) {
- BannerModSettlementResidentScheduleSeed scheduleSeed = BannerModSettlementResidentScheduleSeed.defaultFor(BannerModSettlementResidentRole.CONTROLLED_WORKER, worker.getBoundWorkAreaUUID());
- BannerModSettlementResidentMode residentMode = BannerModSettlementResidentMode.defaultFor(BannerModSettlementResidentRole.CONTROLLED_WORKER, worker.getOwnerUUID());
- BannerModSettlementResidentAssignmentState assignmentState = worker.getBoundWorkAreaUUID() == null
- ? BannerModSettlementResidentAssignmentState.UNASSIGNED
- : BannerModSettlementResidentAssignmentState.ASSIGNED_MISSING_BUILDING;
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed = BannerModSettlementResidentRuntimeRoleSeed.defaultFor(
- BannerModSettlementResidentRole.CONTROLLED_WORKER,
+ SettlementResidentScheduleSeed scheduleSeed = SettlementResidentScheduleSeed.defaultFor(SettlementResidentRole.CONTROLLED_WORKER, worker.getBoundWorkAreaUUID());
+ SettlementResidentMode residentMode = SettlementResidentMode.defaultFor(SettlementResidentRole.CONTROLLED_WORKER, worker.getOwnerUUID());
+ SettlementResidentAssignmentState assignmentState = worker.getBoundWorkAreaUUID() == null
+ ? SettlementResidentAssignmentState.UNASSIGNED
+ : SettlementResidentAssignmentState.ASSIGNED_MISSING_BUILDING;
+ SettlementResidentRuntimeRoleState runtimeRoleState = SettlementResidentRuntimeRoleState.defaultFor(
+ SettlementResidentRole.CONTROLLED_WORKER,
scheduleSeed,
residentMode,
assignmentState
);
- residents.put(worker.getUUID(), new BannerModSettlementResidentRecord(
+ residents.put(worker.getUUID(), new SettlementResidentRecord(
worker.getUUID(),
- BannerModSettlementResidentRole.CONTROLLED_WORKER,
+ SettlementResidentRole.CONTROLLED_WORKER,
scheduleSeed,
- BannerModSettlementResidentScheduleWindowSeed.defaultFor(scheduleSeed, runtimeRoleSeed),
- runtimeRoleSeed,
- BannerModSettlementResidentServiceContract.defaultFor(BannerModSettlementResidentRole.CONTROLLED_WORKER, residentMode, assignmentState, worker.getBoundWorkAreaUUID(), null),
- BannerModSettlementResidentJobDefinition.defaultFor(
- BannerModSettlementResidentRole.CONTROLLED_WORKER,
- runtimeRoleSeed,
- BannerModSettlementResidentServiceContract.defaultFor(BannerModSettlementResidentRole.CONTROLLED_WORKER, residentMode, assignmentState, worker.getBoundWorkAreaUUID(), null),
+ SettlementResidentScheduleWindowSeed.defaultFor(scheduleSeed, runtimeRoleState),
+ runtimeRoleState,
+ SettlementResidentServiceContract.defaultFor(SettlementResidentRole.CONTROLLED_WORKER, residentMode, assignmentState, worker.getBoundWorkAreaUUID(), null),
+ SettlementResidentJobDefinition.defaultFor(
+ SettlementResidentRole.CONTROLLED_WORKER,
+ runtimeRoleState,
+ SettlementResidentServiceContract.defaultFor(SettlementResidentRole.CONTROLLED_WORKER, residentMode, assignmentState, worker.getBoundWorkAreaUUID(), null),
null
),
residentMode,
@@ -159,24 +119,24 @@ static List collectResidents(ServerLevel leve
));
}
if (governorSnapshot != null && governorSnapshot.governorRecruitUuid() != null) {
- residents.put(governorSnapshot.governorRecruitUuid(), new BannerModSettlementResidentRecord(
+ residents.put(governorSnapshot.governorRecruitUuid(), new SettlementResidentRecord(
governorSnapshot.governorRecruitUuid(),
- BannerModSettlementResidentRole.GOVERNOR_RECRUIT,
- BannerModSettlementResidentScheduleSeed.GOVERNING,
- BannerModSettlementResidentScheduleWindowSeed.CIVIC_DAY,
- BannerModSettlementResidentRuntimeRoleSeed.GOVERNANCE,
- BannerModSettlementResidentServiceContract.notServiceActor(),
- BannerModSettlementResidentJobDefinition.defaultFor(
- BannerModSettlementResidentRole.GOVERNOR_RECRUIT,
- BannerModSettlementResidentRuntimeRoleSeed.GOVERNANCE,
- BannerModSettlementResidentServiceContract.notServiceActor(),
+ SettlementResidentRole.GOVERNOR_RECRUIT,
+ SettlementResidentScheduleSeed.GOVERNING,
+ SettlementResidentScheduleWindowSeed.CIVIC_DAY,
+ SettlementResidentRuntimeRoleState.GOVERNANCE,
+ SettlementResidentServiceContract.notServiceActor(),
+ SettlementResidentJobDefinition.defaultFor(
+ SettlementResidentRole.GOVERNOR_RECRUIT,
+ SettlementResidentRuntimeRoleState.GOVERNANCE,
+ SettlementResidentServiceContract.notServiceActor(),
null
),
- BannerModSettlementResidentMode.SETTLEMENT_RESIDENT,
+ SettlementResidentMode.SETTLEMENT_RESIDENT,
governorSnapshot.governorOwnerUuid(),
settlementFactionId,
null,
- BannerModSettlementResidentAssignmentState.NOT_APPLICABLE
+ SettlementResidentAssignmentState.NOT_APPLICABLE
));
}
return new ArrayList<>(residents.values());
@@ -191,56 +151,56 @@ public static List workersInClaim(ServerLevel level, Recru
});
}
- static List applyResidentAssignmentSemantics(List residents,
+ static List applyResidentAssignmentSemantics(List residents,
Set localBuildingUuids) {
if (residents.isEmpty()) {
return List.of();
}
- List updatedResidents = new ArrayList<>(residents.size());
- for (BannerModSettlementResidentRecord resident : residents) {
- if (resident.role() != BannerModSettlementResidentRole.CONTROLLED_WORKER) {
+ List updatedResidents = new ArrayList<>(residents.size());
+ for (SettlementResidentRecord resident : residents) {
+ if (resident.role() != SettlementResidentRole.CONTROLLED_WORKER) {
updatedResidents.add(resident);
continue;
}
- BannerModSettlementResidentAssignmentState assignmentState;
+ SettlementResidentAssignmentState assignmentState;
if (resident.boundWorkAreaUuid() == null) {
- assignmentState = BannerModSettlementResidentAssignmentState.UNASSIGNED;
+ assignmentState = SettlementResidentAssignmentState.UNASSIGNED;
} else if (localBuildingUuids.contains(resident.boundWorkAreaUuid())) {
- assignmentState = BannerModSettlementResidentAssignmentState.ASSIGNED_LOCAL_BUILDING;
+ assignmentState = SettlementResidentAssignmentState.ASSIGNED_LOCAL_BUILDING;
} else {
- assignmentState = BannerModSettlementResidentAssignmentState.ASSIGNED_MISSING_BUILDING;
+ assignmentState = SettlementResidentAssignmentState.ASSIGNED_MISSING_BUILDING;
}
- BannerModSettlementResidentRuntimeRoleSeed runtimeRoleSeed = BannerModSettlementResidentRuntimeRoleSeed.defaultFor(
+ SettlementResidentRuntimeRoleState runtimeRoleState = SettlementResidentRuntimeRoleState.defaultFor(
resident.role(),
resident.scheduleSeed(),
resident.residentMode(),
assignmentState
);
- BannerModSettlementResidentScheduleWindowSeed scheduleWindowSeed = BannerModSettlementResidentScheduleWindowSeed.defaultFor(
+ SettlementResidentScheduleWindowSeed scheduleWindowSeed = SettlementResidentScheduleWindowSeed.defaultFor(
resident.scheduleSeed(),
- runtimeRoleSeed
+ runtimeRoleState
);
- updatedResidents.add(new BannerModSettlementResidentRecord(
+ updatedResidents.add(new SettlementResidentRecord(
resident.residentUuid(),
resident.role(),
resident.scheduleSeed(),
scheduleWindowSeed,
- runtimeRoleSeed,
+ runtimeRoleState,
resident.serviceContract(),
resident.jobDefinition(),
- resident.jobTargetSelectionSeed(),
+ resident.jobTargetSelectionState(),
resident.residentMode(),
resident.ownerUuid(),
resident.teamId(),
resident.boundWorkAreaUuid(),
assignmentState,
- BannerModSettlementResidentRoleProfile.defaultFor(
+ SettlementResidentRoleProfile.defaultFor(
resident.role(),
- runtimeRoleSeed,
+ runtimeRoleState,
resident.residentMode(),
assignmentState
)
@@ -249,38 +209,38 @@ static List applyResidentAssignmentSemantics(
return updatedResidents;
}
- static List applyResidentServiceContracts(List residents,
- List buildings) {
+ static List applyResidentServiceContracts(List residents,
+ List buildings) {
if (residents.isEmpty()) {
return List.of();
}
- Map buildingsByUuid = new LinkedHashMap<>();
- for (BannerModSettlementBuildingRecord building : buildings) {
+ Map buildingsByUuid = new LinkedHashMap<>();
+ for (SettlementBuildingRecord building : buildings) {
buildingsByUuid.put(building.buildingUuid(), building);
}
- List updatedResidents = new ArrayList<>(residents.size());
- for (BannerModSettlementResidentRecord resident : residents) {
- BannerModSettlementBuildingRecord serviceBuilding = resident.boundWorkAreaUuid() == null
+ List updatedResidents = new ArrayList<>(residents.size());
+ for (SettlementResidentRecord resident : residents) {
+ SettlementBuildingRecord serviceBuilding = resident.boundWorkAreaUuid() == null
? null
: buildingsByUuid.get(resident.boundWorkAreaUuid());
- BannerModSettlementResidentServiceContract serviceContract = BannerModSettlementResidentServiceContract.defaultFor(
+ SettlementResidentServiceContract serviceContract = SettlementResidentServiceContract.defaultFor(
resident.role(),
resident.residentMode(),
resident.assignmentState(),
resident.boundWorkAreaUuid(),
serviceBuilding == null ? null : serviceBuilding.buildingTypeId()
);
- updatedResidents.add(new BannerModSettlementResidentRecord(
+ updatedResidents.add(new SettlementResidentRecord(
resident.residentUuid(),
resident.role(),
resident.scheduleSeed(),
resident.scheduleWindowSeed(),
- resident.runtimeRoleSeed(),
+ resident.runtimeRoleState(),
serviceContract,
resident.jobDefinition(),
- resident.jobTargetSelectionSeed(),
+ resident.jobTargetSelectionState(),
resident.residentMode(),
resident.ownerUuid(),
resident.teamId(),
@@ -292,37 +252,37 @@ static List applyResidentServiceContracts(Lis
return updatedResidents;
}
- static List applyResidentJobDefinitions(List residents,
- List buildings) {
+ static List applyResidentJobDefinitions(List residents,
+ List buildings) {
if (residents.isEmpty()) {
return List.of();
}
- Map buildingsByUuid = new LinkedHashMap<>();
- for (BannerModSettlementBuildingRecord building : buildings) {
+ Map buildingsByUuid = new LinkedHashMap<>();
+ for (SettlementBuildingRecord building : buildings) {
buildingsByUuid.put(building.buildingUuid(), building);
}
- List updatedResidents = new ArrayList<>(residents.size());
- for (BannerModSettlementResidentRecord resident : residents) {
- BannerModSettlementBuildingRecord targetBuilding = resident.serviceContract().serviceBuildingUuid() == null
+ List updatedResidents = new ArrayList<>(residents.size());
+ for (SettlementResidentRecord resident : residents) {
+ SettlementBuildingRecord targetBuilding = resident.serviceContract().serviceBuildingUuid() == null
? null
: buildingsByUuid.get(resident.serviceContract().serviceBuildingUuid());
- BannerModSettlementResidentJobDefinition jobDefinition = BannerModSettlementResidentJobDefinition.defaultFor(
+ SettlementResidentJobDefinition jobDefinition = SettlementResidentJobDefinition.defaultFor(
resident.role(),
- resident.runtimeRoleSeed(),
+ resident.runtimeRoleState(),
resident.serviceContract(),
targetBuilding
);
- updatedResidents.add(new BannerModSettlementResidentRecord(
+ updatedResidents.add(new SettlementResidentRecord(
resident.residentUuid(),
resident.role(),
resident.scheduleSeed(),
resident.scheduleWindowSeed(),
- resident.runtimeRoleSeed(),
+ resident.runtimeRoleState(),
resident.serviceContract(),
jobDefinition,
- resident.jobTargetSelectionSeed(),
+ resident.jobTargetSelectionState(),
resident.residentMode(),
resident.ownerUuid(),
resident.teamId(),
@@ -334,29 +294,29 @@ static List applyResidentJobDefinitions(List<
return updatedResidents;
}
- static List