Skip to content
This repository was archived by the owner on Aug 31, 2026. It is now read-only.

Commit f59cce9

Browse files
committed
feat: a gun that tracks a target and knows whose side it is on
- follow an entity, not only a point, and lose it when it dies - spare a target carrying the installation's access code - declare what a build needs delivered, gas included and reserved - add manual control as a mode through the same launch path - read mount telemetry off the guns for the console readout - pin the ship-frame case: a gun in the shipyard fires into the world
1 parent 965d8fc commit f59cce9

10 files changed

Lines changed: 793 additions & 11 deletions

File tree

‎src/main/java/zmaster587/advancedRocketry/AdvancedRocketry.java‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,8 @@ public void registerBlocks(RegistryEvent.Register<Block> evt) {
742742
.setUnlocalizedName("gunBarrel").setCreativeTab(tabAdvRocketry);
743743
AdvancedRocketryBlocks.blockGunAmmoFeed = new zmaster587.advancedRocketry.block.weapon.BlockGunPart(
744744
builder -> builder.speedUpFireIntervalBy(3).addImpactEnergy(6).addEnergyPerShot(75)
745-
.addHeatPerShot(2))
745+
.addHeatPerShot(2)
746+
.declareInput(zmaster587.advancedRocketry.api.weapon.GunInput.FORGE_ENERGY))
746747
.setUnlocalizedName("gunAmmoFeed").setCreativeTab(tabAdvRocketry);
747748
AdvancedRocketryBlocks.blockGunCooling = new zmaster587.advancedRocketry.block.weapon.BlockGunPart(
748749
builder -> builder.addHeatCapacity(40).addCoolingPerTick(2).addTraverseDegreesPerTick(0.5D))
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package zmaster587.advancedRocketry.api.weapon;
2+
3+
/**
4+
* What a gun needs delivered to it in order to fire.
5+
*
6+
* <h3>Declared by the build, so nothing has to guess</h3>
7+
* <p>A gun states its inputs rather than being asked to justify a failure to fire: a player looking
8+
* at a silent weapon can be told "it wants gas and has none" instead of being left to work out which
9+
* of six conditions is unmet. An addon's part declares its own input the same way, which is what
10+
* lets a supply system serve weapons it was not written knowing about.</p>
11+
*
12+
* <h3>One of these is implemented</h3>
13+
* <p>{@link #FORGE_ENERGY} is real: guns hold a buffer, draw from any FE source, and the weapons
14+
* network distributes it. {@link #GAS} is declared and reserved — the fabric that would carry it
15+
* exists for other purposes, and the plasma weapons that would want it are a later wave. A build
16+
* that declares it today is not refused and is not charged; the declaration is what makes adding the
17+
* supply later a change to one place rather than to every gun.</p>
18+
*/
19+
public enum GunInput {
20+
21+
/** Forge Energy, drawn from the gun's own buffer. Implemented. */
22+
FORGE_ENERGY,
23+
24+
/** A gas feed from the ship's fabric. Declared only — nothing consumes it yet. */
25+
GAS
26+
}

‎src/main/java/zmaster587/advancedRocketry/api/weapon/GunSpec.java‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public final class GunSpec {
4040
private final double projectileMass;
4141
private final ImpactKind kind;
4242
private final int partCount;
43+
private final java.util.EnumSet<GunInput> inputs;
4344

4445
private GunSpec(Builder builder) {
4546
this.muzzleSpeed = builder.muzzleSpeed;
@@ -56,6 +57,8 @@ private GunSpec(Builder builder) {
5657
this.projectileMass = builder.projectileMass;
5758
this.kind = builder.kind;
5859
this.partCount = builder.partCount;
60+
this.inputs = java.util.EnumSet.copyOf(builder.inputs.isEmpty()
61+
? java.util.EnumSet.of(GunInput.FORGE_ENERGY) : builder.inputs);
5962
}
6063

6164
/**
@@ -127,6 +130,14 @@ public ImpactKind getKind() {
127130
return kind;
128131
}
129132

133+
/**
134+
* What this build needs delivered to it. Never empty: a gun that declared nothing would be a gun
135+
* nothing could be said about, so the floor is Forge Energy — which every build draws anyway.
136+
*/
137+
public java.util.Set<GunInput> getDeclaredInputs() {
138+
return java.util.Collections.unmodifiableSet(inputs);
139+
}
140+
130141
/** How many parts were counted. Diagnostics, and the "is this thing built" test's raw material. */
131142
public int getPartCount() {
132143
return partCount;
@@ -157,6 +168,7 @@ public static final class Builder {
157168
private double projectileMass = 1.0D;
158169
private ImpactKind kind = ImpactKind.KINETIC;
159170
private int partCount;
171+
private final java.util.EnumSet<GunInput> inputs = java.util.EnumSet.noneOf(GunInput.class);
160172

161173
public Builder addMuzzleSpeed(double blocksPerTick) {
162174
this.muzzleSpeed += Math.max(0.0D, blocksPerTick);
@@ -227,6 +239,17 @@ public Builder setKind(ImpactKind kind) {
227239
return this;
228240
}
229241

242+
/**
243+
* State that this part needs something delivered. Additive like everything else: a build with
244+
* one gas-fed component declares gas, whatever the rest of it wants.
245+
*/
246+
public Builder declareInput(GunInput input) {
247+
if (input != null) {
248+
this.inputs.add(input);
249+
}
250+
return this;
251+
}
252+
230253
/** Called once per part counted, by the assembly walk rather than by the parts themselves. */
231254
public Builder countPart() {
232255
this.partCount++;

‎src/main/java/zmaster587/advancedRocketry/command/test/TestProbeCommand.java‎

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ private void handleTurret(MinecraftServer server, ICommandSender sender, String[
399399
}
400400
if ("cleartarget".equals(sub)) {
401401
turret.setTarget(null);
402+
turret.setTargetEntity(null);
402403
send(sender, "{\"ok\":true}");
403404
return;
404405
}
@@ -413,6 +414,36 @@ private void handleTurret(MinecraftServer server, ICommandSender sender, String[
413414
send(sender, "{\"ok\":true,\"drive\":\"" + turret.getMechanism().getDriveState().name() + "\"}");
414415
return;
415416
}
417+
if ("target-player".equals(sub) && args.length >= 6) {
418+
net.minecraft.entity.player.EntityPlayerMP player =
419+
server.getPlayerList().getPlayerByUsername(args[5]);
420+
if (player == null) {
421+
send(sender, jsonError("no such player"));
422+
return;
423+
}
424+
turret.setTargetEntity(player.getUniqueID());
425+
send(sender, "{\"ok\":true}");
426+
return;
427+
}
428+
if ("code".equals(sub)) {
429+
turret.setAccessCode(args.length >= 6 ? args[5] : "");
430+
send(sender, "{\"ok\":true,\"code\":\"" + escapeJson(turret.getEffectiveAccessCode()) + "\"}");
431+
return;
432+
}
433+
if ("manual".equals(sub) && args.length >= 6) {
434+
turret.setManualControl(Boolean.parseBoolean(args[5]));
435+
send(sender, "{\"ok\":true,\"manual\":" + turret.isManuallyControlled() + "}");
436+
return;
437+
}
438+
if ("bearing".equals(sub) && args.length >= 7) {
439+
turret.commandManualBearing(parseDoubleOr(args[5], 0), parseDoubleOr(args[6], 0));
440+
send(sender, "{\"ok\":true}");
441+
return;
442+
}
443+
if ("fire".equals(sub)) {
444+
send(sender, "{\"ok\":true,\"fired\":" + turret.fireOnce() + "}");
445+
return;
446+
}
416447
if ("read".equals(sub)) {
417448
zmaster587.advancedRocketry.api.weapon.GunSpec spec = turret.getSpec();
418449
zmaster587.advancedRocketry.weapon.TurretMechanism mount = turret.getMechanism();
@@ -436,6 +467,10 @@ private void handleTurret(MinecraftServer server, ICommandSender sender, String[
436467
+ ",\"drive\":\"" + mount.getDriveState().name() + "\""
437468
+ ",\"shots\":" + turret.getShotsFired()
438469
+ ",\"lastShot\":" + turret.getLastShotId()
470+
+ ",\"trackingEntity\":" + (turret.getTargetEntity() != null)
471+
+ ",\"code\":\"" + escapeJson(turret.getEffectiveAccessCode()) + "\""
472+
+ ",\"manual\":" + turret.isManuallyControlled()
473+
+ ",\"inputs\":\"" + escapeJson(spec.getDeclaredInputs().toString()) + "\""
439474
+ ",\"hasTarget\":" + (target != null)
440475
+ (target == null ? "" : ",\"targetX\":" + target.x + ",\"targetY\":" + target.y
441476
+ ",\"targetZ\":" + target.z)
@@ -496,13 +531,34 @@ private void handleWeaponConsole(MinecraftServer server, ICommandSender sender,
496531
+ console.isHoldFire() + "}");
497532
return;
498533
}
534+
if ("target-player".equals(sub) && args.length >= 6) {
535+
net.minecraft.entity.player.EntityPlayerMP player =
536+
server.getPlayerList().getPlayerByUsername(args[5]);
537+
if (player == null) {
538+
send(sender, jsonError("no such player"));
539+
return;
540+
}
541+
send(sender, "{\"ok\":true,\"applied\":"
542+
+ console.assignTargetEntity(player.getUniqueID()) + "}");
543+
return;
544+
}
545+
if ("code".equals(sub)) {
546+
boolean applied = console.setAccessCode(args.length >= 6 ? args[5] : "");
547+
send(sender, "{\"ok\":true,\"applied\":" + applied + ",\"code\":\""
548+
+ escapeJson(console.getAccessCode()) + "\"}");
549+
return;
550+
}
499551
if ("read".equals(sub)) {
500552
net.minecraft.util.math.Vec3d target = console.getTarget();
501553
send(sender, "{\"ok\":true"
502554
+ ",\"network\":" + (console.network() != null)
503555
+ ",\"status\":\"" + escapeJson(console.getNetworkStatusText()) + "\""
504556
+ ",\"guns\":" + console.getGunCount()
557+
+ ",\"onTarget\":" + console.getMountTelemetry()[0]
558+
+ ",\"saturated\":" + console.getMountTelemetry()[1]
505559
+ ",\"holdFire\":" + console.isHoldFire()
560+
+ ",\"code\":\"" + escapeJson(console.getAccessCode()) + "\""
561+
+ ",\"trackingEntity\":" + (console.getTargetEntity() != null)
506562
+ ",\"hasTarget\":" + (target != null)
507563
+ (target == null ? "" : ",\"targetX\":" + target.x + ",\"targetY\":" + target.y
508564
+ ",\"targetZ\":" + target.z)
@@ -512,6 +568,11 @@ private void handleWeaponConsole(MinecraftServer server, ICommandSender sender,
512568
send(sender, "{\"error\":\"unknown weaponconsole subcommand\",\"sub\":\"" + escapeJson(sub) + "\"}");
513569
}
514570

571+
/** One-line error payload, so a new verb does not hand-build JSON and get a quote wrong. */
572+
private static String jsonError(String message) {
573+
return "{\"error\":\"" + escapeJson(message) + "\"}";
574+
}
575+
515576
private static String shotJson(zmaster587.advancedRocketry.projectile.Shot shot) {
516577
return "{\"id\":" + shot.getId()
517578
+ ",\"x\":" + shot.getPosition().x

0 commit comments

Comments
 (0)