diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3e23ccc..6aec5cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -108,9 +108,9 @@ jobs: if-no-files-found: error retention-days: 30 path: | - build/libs/SteamAdvantage-2.2.4.110021.jar - build/libs/SteamAdvantage-2.2.4.110021-sources.jar - build/libs/SteamAdvantage-2.2.4.110021-javadoc.jar + build/libs/SteamAdvantage-2.2.5.110021.jar + build/libs/SteamAdvantage-2.2.5.110021-sources.jar + build/libs/SteamAdvantage-2.2.5.110021-javadoc.jar build/release/SHA256SUMS CHANGELOG.txt diff --git a/.gitignore b/.gitignore index 4502811..4933367 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,25 @@ /replay_pid*.log /secret.json +# Nested local tooling and generated output +AGENTS.md +AGENT.md +CLAUDE.md +GEMINI.md +ARCHITECT.md +agent-notes/ +.codex/ +.agent/ +.agents/ +.claude/ +.gemini/ +.cursor/ +agent-*.md +codex-*.md +*.log +*.class +__pycache__/ +*.pyc /.DS_Store /README.txt /forge-*-changelog.txt diff --git a/CHANGELOG.txt b/CHANGELOG.txt index f3c595e..28f0640 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,10 @@ +Steam Advantage 2.2.5.110021 + +- Retain unfinished drill progress when rebuilding the mining target after a world or chunk reload. +- Clear stale deferred target data when loading an untargeted tile; clamp restored progress to current target hardness. +- Refresh the drill's redstone state before its first resumed tick so saved work is not discarded by an uninitialized control cache. +- Preserve registry identities, saved target coordinates, inventories, energy and the existing progress NBT key. + Steam Advantage 2.2.4.110021 - Move the implementation namespace to zone.moddev.mc.steamadvantage while preserving runtime identities. diff --git a/README.md b/README.md index 2c9eb8f..70d8022 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,12 @@ tile-entity, asset, configuration, and saved-world identities are unchanged. The cross-mod [Advantage Works 1.10.2 Handbook](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.10.2/docs/1.10/README.md) includes the Steam Engineer's Handbook, rated figures, commissioning layouts, and persistence tests. The [MMD material and fluid compatibility specification](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.10.2/docs/1.10/mmd-material-fluid-compatibility.md) defines crude-oil aliases and OreSpawn ownership. +## Drill Reload Fix + +Version `2.2.5.110021` keeps unfinished drill work when a chunk or world reloads. +Existing inventories, energy, orientation and saved-world names are unchanged. +The regression tests cover resumed progress and full server restarts. + ## Building Minecraft 1.10.2 The `master-1.10.2` build uses ForgeGradle 7.0.34 and Gradle 9.6.1. Run Gradle with Java 17; Gradle resolves the Java 8 toolchain used for compilation. diff --git a/build.gradle b/build.gradle index 4b19b70..3059b82 100644 --- a/build.gradle +++ b/build.gradle @@ -181,6 +181,8 @@ dependencies { compileOnly files(powerAdvantageDeobfJar) runtimeOnly files(powerAdvantageDeobfJar) runtimeOnly files(oreSpawnDeobfJar) + testImplementation files(powerAdvantageDeobfJar) + testImplementation 'junit:junit:4.13.2' } tasks.named('processResources', ProcessResources) { @@ -282,7 +284,7 @@ tasks.register('verifyReleaseConfiguration') { group = 'verification' description = 'Validates release identity, target metadata, and dependency policy.' doLast { - if (project.mod_version != '2.2.4.110021') { + if (project.mod_version != '2.2.5.110021') { throw new GradleException("Unexpected SteamAdvantage release version: ${project.mod_version}") } if (project.minecraft_version != '1.10.2' @@ -333,7 +335,7 @@ tasks.register('verifyReleaseConfiguration') { String mainSource = file( 'src/main/java/zone/moddev/mc/steamadvantage/SteamAdvantage.java').getText('UTF-8') if (!mainSource.contains('MODID = "steamadvantage"') - || !mainSource.contains('VERSION = "2.2.4.110021"') + || !mainSource.contains('VERSION = "2.2.5.110021"') || !mainSource.contains('dependencies = "required-after:poweradvantage@[2.4.3.110021,);after:basemetals"')) { throw new GradleException('SteamAdvantage source identity or dependency policy changed') } diff --git a/gradle.properties b/gradle.properties index a76e79e..8ebcf2d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,7 +24,7 @@ curseforge_project_id=240984 mod_id=steamadvantage mod_name=Steam Advantage mod_license=GPL-3.0-only -mod_version=2.2.4.110021 +mod_version=2.2.5.110021 mod_group=zone.moddev.mc.steamadvantage mod_authors=DrCyano mod_description=Steam-powered machines and infrastructure for the Power Advantage platform. diff --git a/src/main/java/zone/moddev/mc/steamadvantage/SteamAdvantage.java b/src/main/java/zone/moddev/mc/steamadvantage/SteamAdvantage.java index 9452327..3693ae7 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/SteamAdvantage.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/SteamAdvantage.java @@ -42,7 +42,7 @@ public class SteamAdvantage /** The display name for this mod */ public static final String NAME = "Steam Advantage"; /** The target-qualified release version of this mod. */ - public static final String VERSION = "2.2.4.110021"; + public static final String VERSION = "2.2.5.110021"; public static float MUSKET_DAMAGE = 20; public static int MUSKET_RELOAD = 20*5; diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamDrillTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamDrillTileEntity.java index af48083..f947c7c 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamDrillTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamDrillTileEntity.java @@ -59,7 +59,7 @@ public SteamDrillTileEntity() { public void tickUpdate(boolean isServerWorld) { if(isServerWorld){ if(deferred){ - targetBlock(targetBlockCoord); + restoreTargetBlock(); } EnumFacing face = this.getFacing(); if(oldDir == null){ @@ -226,7 +226,7 @@ public void onDataFieldUpdate() { private int oldProgress = 0; @Override public void powerUpdate(){ if(deferred){ - targetBlock(targetBlockCoord); + restoreTargetBlock(); } super.powerUpdate(); boolean flagSync = progress != oldProgress || oldEnergy != getEnergy(Power.steam_power); @@ -334,12 +334,21 @@ private void targetBlock (BlockPos n){ deferred = false; } + private void restoreTargetBlock(){ + int savedProgress = progress; + // Rebuild transient drops and hardness without discarding saved work. + targetBlock(targetBlockCoord); + progress = Math.max(0, Math.min(savedProgress, progressGoal)); + redstone = hasRedstoneSignal(); + } + private void deferredTargetBlock (BlockPos n){ targetBlockCoord = n; deferred = true; } private void untargetBlock(){ + deferred = false; progress = 0; progressGoal = 0; targetBlockCoord = null; @@ -453,6 +462,7 @@ public NBTTagCompound writeToNBT(NBTTagCompound tagRoot){ @Override public void readFromNBT(NBTTagCompound tagRoot){ super.readFromNBT(tagRoot); + untargetBlock(); if(tagRoot.hasKey("Facing")){ int facingIndex = tagRoot.getByte("Facing"); if(facingIndex >= 0 && facingIndex < EnumFacing.values().length){ @@ -470,7 +480,8 @@ public void readFromNBT(NBTTagCompound tagRoot){ if(powerAdvantageWorld() == null){ this.deferredTargetBlock(new BlockPos(x,y,z)); } else { - this.targetBlock(new BlockPos(x,y,z)); + this.deferredTargetBlock(new BlockPos(x,y,z)); + this.restoreTargetBlock(); } } } diff --git a/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamDrillPersistenceTest.java b/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamDrillPersistenceTest.java new file mode 100644 index 0000000..31f9763 --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamDrillPersistenceTest.java @@ -0,0 +1,35 @@ +package zone.moddev.mc.steamadvantage.machines; + +import net.minecraft.nbt.NBTTagCompound; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class SteamDrillPersistenceTest { + @Test public void retainsLegacyProgressBeforeWorldAttachment() { + SteamDrillTileEntity drill = new SteamDrillTileEntity(); + drill.readFromNBT(target(17)); + drill.prepareDataFieldsForSync(); + assertEquals(17, drill.getDataFieldArray()[1]); + } + + @Test public void untargetedDataClearsPendingWork() throws Exception { + SteamDrillTileEntity drill = new SteamDrillTileEntity(); + drill.readFromNBT(target(17)); + drill.readFromNBT(new NBTTagCompound()); + drill.prepareDataFieldsForSync(); + assertEquals(0, drill.getDataFieldArray()[1]); + java.lang.reflect.Field target = SteamDrillTileEntity.class.getDeclaredField("targetBlockCoord"); + target.setAccessible(true); + assertNull(target.get(drill)); + } + + private static NBTTagCompound target(int progress) { + NBTTagCompound tag = new NBTTagCompound(); + tag.setShort("progress", (short) progress); + tag.setInteger("targetX", 2048); + tag.setInteger("targetY", 80); + tag.setInteger("targetZ", 2049); + return tag; + } +}