Skip to content

Commit a1fe292

Browse files
committed
Big changes to how aiming is done, although more complex should be more intuitive, worst case gives me more knobs to tune until it is. Will add writeup to readme later.
1 parent 970bcbd commit a1fe292

File tree

6 files changed

+414
-180
lines changed

6 files changed

+414
-180
lines changed

src/main/java/com/programmerdan/minecraft/addgun/ammo/Bullet.java

Lines changed: 23 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -163,63 +163,34 @@ public double getFireChance() {
163163
/**
164164
* Knockback on hit
165165
*/
166-
private int knockback = 0;
166+
private double knockbackAvg = 0;
167167
/**
168-
* Chance of knockback.
169-
*/
170-
private double knockbackChance = 0.0d;
171-
172-
/**
173-
* The point at which, after so many seconds of "stillness" -- head motion only -- that any aim impacts are halved.
174-
* Additive to gun base. Some bullets are harder to fire.
175-
*/
176-
private double stillInflection = 0.0d;
177-
/**
178-
* The point at which, after so many seconds of sneaking, any aim impacts are halved.
168+
* Wiggle on avg
179169
*/
180-
private double sneakInflection = 0.0d;
170+
private double knockbackSpread = 0;
181171
/**
182-
* A relative "spread" of speed of motion over inflection, values close to 0 lead to a sharp inflection, values larger make a smoother
183-
* transition. This is for stillness. Adds to gun spread, so keep this reasonable.
172+
* Chance of knockback.
184173
*/
185-
private double stillSpread = 0.0d;
174+
private double knockbackChance = 0.0d;
186175
/**
187-
* A relative "spread" of speed of motion over inflection, values close to 0 lead to a sharp inflection, values larger make a smoother
188-
* transition. This is for sneaking.
176+
* Is knockback attenuated by armor reduction?
189177
*/
190-
private double sneakSpread = 0.0d;
191-
192-
193-
public double getStillInflection() {
194-
return stillInflection;
195-
}
178+
private boolean knockbackIgnoreReduction = false;
196179

197-
public void setStillInflection(double stillInflection) {
198-
this.stillInflection = stillInflection;
180+
public double getKnockbackChance() {
181+
return knockbackChance;
199182
}
200-
201-
public double getSneakInflection() {
202-
return sneakInflection;
203-
}
204-
205-
public void setSneakInflection(double sneakInflection) {
206-
this.sneakInflection = sneakInflection;
207-
}
208-
209-
public double getStillSpread() {
210-
return stillSpread;
211-
}
212-
213-
public void setStillSpread(double stillSpread) {
214-
this.stillSpread = stillSpread;
183+
184+
public double getKnockbackAvg() {
185+
return knockbackAvg;
215186
}
216-
217-
public double getSneakSpread() {
218-
return sneakSpread;
187+
188+
public double getKnockbackSpread() {
189+
return knockbackSpread;
219190
}
220-
221-
public void setSneakSpread(double sneakSpread) {
222-
this.sneakSpread = sneakSpread;
191+
192+
public boolean getKnockbackIgnoreReduction() {
193+
return knockbackIgnoreReduction;
223194
}
224195

225196
// bypass stuff is TODO
@@ -287,11 +258,11 @@ public Bullet(ConfigurationSection config) {
287258
this.xpDraw = config.getInt("xpPerShot", xpDraw);
288259
this.maxMissRadius = config.getDouble("missRadius.max", maxMissRadius);
289260
this.minMissRadius = config.getDouble("missRadius.min", minMissRadius);
290-
291-
this.sneakInflection = config.getDouble("sneak.inflection", sneakInflection);
292-
this.sneakSpread = config.getDouble("sneak.spread", sneakSpread);
293-
this.stillInflection = config.getDouble("still.inflection", stillInflection);
294-
this.stillSpread = config.getDouble("still.spread", stillSpread);
261+
262+
this.knockbackChance = config.getDouble("knockback.chance", knockbackChance);
263+
this.knockbackAvg = config.getDouble("knockback.avg", knockbackAvg);
264+
this.knockbackSpread = config.getDouble("knockback.spread", knockbackSpread);
265+
this.knockbackIgnoreReduction = config.getBoolean("knockback.ignore-reduction", knockbackIgnoreReduction);
295266

296267
this.avgScatter = config.getInt("scatter.avg", avgScatter);
297268
this.spreadScatter = config.getInt("scatter.spread", spreadScatter);
@@ -303,9 +274,6 @@ public Bullet(ConfigurationSection config) {
303274
this.fireChance = config.getDouble("incendiary.chance", fireChance);
304275
this.fireTicks = config.getInt("incendiary.ticks", fireTicks);
305276

306-
this.knockbackChance = config.getDouble("knockback.chance", knockbackChance);
307-
this.knockback = config.getInt("knockback.level", knockback);
308-
309277
// TODO: damage bypass.
310278
this.baseArmorReduction = config.getDouble("reduction.base", baseArmorReduction);
311279
for (ArmorType armor : ArmorType.values()) {

src/main/java/com/programmerdan/minecraft/addgun/guns/Guns.java

Lines changed: 83 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,8 @@ public void gunPlayerInteractEvent(PlayerInteractEvent event) {
308308
} else {
309309
player.sendMessage(ChatColor.AQUA + gun.getName() + ChatColor.RED + " misfired! Try again.");
310310
}
311+
312+
AddGun.getPlugin().getPlayerListener().recordShotImpact(player.getUniqueId(), gun.getInnateAim(), gun.getInnateAim() / ((gun.getCooldown()*2l) / 50), (int) (gun.getCooldown()*2l) / 50);
311313
} else {
312314
// based on their stillness and settledness.
313315
double accuracy = computeAccuracyFor(gun, bulletType, player);
@@ -323,6 +325,9 @@ public void gunPlayerInteractEvent(PlayerInteractEvent event) {
323325
Location origin = player.getLocation().clone().add(bbOff.getX(), offset, bbOff.getZ());
324326

325327
Location baseLocation = player.getEyeLocation().clone();
328+
Location kick = baseLocation.clone();
329+
330+
double kickback = gun.getKickback();
326331

327332
double minJitter = gun.getMinMissRadius() + bulletType.getMinMissRadius();
328333
double maxJitter = gun.getMaxMissRadius() + bulletType.getMaxMissRadius();
@@ -344,8 +349,14 @@ public void gunPlayerInteractEvent(PlayerInteractEvent event) {
344349
float pitchJitter = (float) (((rand2 * (maxJitter - minJitter)) + Math.signum(rand2) * minJitter) * accuracy);
345350
baseLocation.setYaw(baseLocation.getYaw() + yawJitter);
346351
baseLocation.setPitch(baseLocation.getPitch() + pitchJitter);
352+
353+
float kickYaw = yawJitter + (float) (Math.signum(rand1) * kickback);
354+
float kickPitch = pitchJitter + (float) (Math.signum(rand2) * kickback);
355+
kick.setYaw(kick.getYaw() + kickYaw);
356+
kick.setPitch(kick.getPitch() + kickPitch);
357+
347358
if (accuracy > 0.25) {
348-
player.sendMessage(ChatColor.AQUA + gun.getName() + ChatColor.RED + " isn't easy to aim. Crouch and hold still to improve accuracy.");
359+
player.sendMessage(ChatColor.AQUA + gun.getName() + ChatColor.RED + " isn't always easy to aim. Try running less, or crouch and hold still to improve accuracy.");
349360
} else if (accuracy < 0.01) {
350361
// TODO: remove
351362
player.sendMessage(ChatColor.AQUA + gun.getName() + ChatColor.GREEN + " is shooting straight, good work.");
@@ -414,9 +425,11 @@ public void run() {
414425
player.setCooldown(gun.getMinimalGun().getType(), (int) (gun.getCooldown() / 50));
415426

416427
// jerk player's view back and reset still
417-
gun.knockback(player, baseLocation.getDirection());
428+
gun.knockback(player, kick.getDirection());
418429

419430
AddGun.getPlugin().getPlayerListener().resetStillSince(player.getUniqueId());
431+
// TODO: figure this stuff out like wtf
432+
AddGun.getPlugin().getPlayerListener().recordShotImpact(player.getUniqueId(), gun.getInnateAim(), gun.getInnateAim() / ((gun.getCooldown()*2l) / 50), (int) (gun.getCooldown()*2l) / 50);
420433
}
421434
}
422435
} else {
@@ -764,42 +777,92 @@ public double computeAccuracyFor(StandardGun gun, Bullet bullet, LivingEntity en
764777

765778

766779
/**
767-
* Internally computes jitter based only on stillness and sneakness.
780+
* Internally computes jitter based on many factors.
768781
*
769782
* @param entity the entity's UUID to check
770783
* @return value from 0 to 1 where 1 is worse and 0 is best
771784
*/
772785
private double computeAccuracyFor(UUID entity, StandardGun gun, Bullet bullet) {
773786
long now = System.currentTimeMillis();
774787
PlayerListener listener = AddGun.getPlugin().getPlayerListener();
788+
789+
double gunroot = gun.getInnateMiss();
790+
double root = gun.getInnateBase();
791+
775792
Long sneak = listener.getSneakingSince(entity);
776793
Long still = listener.getStillSince(entity);
794+
Long notsneak = listener.getSneakingEnd(entity);
795+
Long notstill = listener.getStillEnd(entity);
777796

797+
// TODO: per-player adjustments.
778798
double base = 1.0d;
779-
if (sneak == null && still == null) { // not sneaking, not still.
780-
return 1.0d;
799+
if (sneak != null) {
800+
// Sneaking reduces baseline impact
801+
base -= 0.025d * (double) ((now - sneak) / 50l);
802+
}
803+
if (still != null) {
804+
// Still reduces baseline impact
805+
base -= 0.05d * (double) ((now - still) / 50l);
806+
}
807+
if (notsneak != null) {
808+
// Not sneaking increases baseline impact
809+
base += 0.025d * (double) ((now - notsneak) / 50l);
810+
}
811+
if (notstill != null) {
812+
// Not still increases baseline impact.
813+
base += 0.05d * (double) ((now - notstill) / 50l);
814+
}
815+
if (base < 0d) base = 0d;
816+
if (base > 1d) base = 1d;
817+
818+
root *= base; // so this is root.
819+
820+
double pbase = 0.0d;
821+
if (still != null) {
822+
// If we are still, reduce "walk" impact.
823+
pbase += 0.1d - 0.00005d * (double) (now - still);
824+
} else if (notstill != null) {
825+
// if we are moving, increase "walk" impact.
826+
pbase += Math.min(0.1d, (0.0001d * (double) (now - notstill)));
827+
}
828+
829+
Long notrun = listener.getSprintingEnd(entity);
830+
Long run = listener.getSprintingSince(entity);
831+
// if we were running, but stopped, linearly impact aim
832+
if (notrun != null) {
833+
pbase += 0.4d - (0.0001d * (double) (now - notrun));
834+
} else if (run != null) {
835+
// if we are running, aim is worsened, up to a max.
836+
pbase += Math.min(0.4d, (0.001d * (double) (now - run)));
837+
}
838+
Long notglide = listener.getGlidingEnd(entity);
839+
Long glide = listener.getGlidingSince(entity);
840+
// Do the same for gliding
841+
if (notglide != null) {
842+
pbase += 0.7d - (0.0001d * (double) (now - notglide));
843+
} else if (glide != null) {
844+
pbase += Math.min(0.7d, (0.001d * (double) (now - glide)));
781845
}
782846

783-
double combineSneakInflection = gun.getSneakInflection() + bullet.getSneakInflection();
784-
if (combineSneakInflection < 0.0d) combineSneakInflection = 0.0d;
847+
// now pull in any impact of prior shots.
848+
pbase += listener.getShotImpact(entity);
785849

786-
double combineStillInflection = gun.getStillInflection() + bullet.getStillInflection();
787-
if (combineStillInflection < 0.0d) combineStillInflection = 0.0d;
850+
if (sneak != null) { // we are sneaking!
851+
// so cut the impacts in half.
852+
pbase /= 2d;
853+
}
788854

789-
double combineSneakSpread = gun.getSneakSpread() + bullet.getSneakSpread();
790-
if (combineSneakSpread < 0.00001d) combineSneakSpread = 0.00001d;
855+
// now add in base.
856+
pbase += root;
857+
// add in root.
858+
pbase += gunroot;
791859

792-
double combineStillSpread = gun.getStillSpread() + bullet.getStillSpread();
793-
if (combineStillSpread < 0.00001d) combineStillSpread = 0.00001d;
860+
if (pbase > 1.0d) pbase = 1.0d;
861+
if (pbase < 0.0d) pbase = 0.0d;
794862

795-
if (sneak != null) { // sneaking
796-
base -= sigmoid((now - sneak) / 1000.0d, combineSneakInflection, 0.25d, combineSneakSpread);
797-
}
798-
if (still != null) { // still
799-
base -= sigmoid((now - still) / 1000.0d, combineStillInflection, 0.25d, combineStillSpread);
800-
}
863+
return pbase; // accuracy is then computed.
801864

802-
return base > 0.0d ? base : 0.0d;
865+
// TODO: These factors should be global...
803866
}
804867

805868
/**
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.programmerdan.minecraft.addgun.guns;
2+
3+
import java.util.Queue;
4+
import java.util.concurrent.atomic.DoubleAccumulator;
5+
6+
/**
7+
* Tracks the shots that have been fired and accumulates their aim disturbing impact.
8+
*
9+
* @author ProgrammerDan
10+
*/
11+
public class ShotTracker implements Runnable {
12+
private Queue<Shot> shotQueue = new java.util.concurrent.ConcurrentLinkedQueue<>();
13+
14+
private DoubleAccumulator offset = new DoubleAccumulator((a,b) -> {return a + b;}, 0.0);
15+
16+
public void addShot(double aimOffset, double decay, int lifetime) {
17+
shotQueue.offer(new Shot(aimOffset, decay, lifetime));
18+
}
19+
20+
public void run() {
21+
DoubleAccumulator offset = new DoubleAccumulator((a,b) -> {return a + b;}, 0.0);
22+
23+
shotQueue.removeIf(s -> {
24+
offset.accumulate(s.decay());
25+
return s.ticksLeft == 0;
26+
});
27+
28+
this.offset = offset;
29+
30+
if (shotQueue.isEmpty()) {
31+
throw new RuntimeException("All done for now for this player");
32+
}
33+
}
34+
35+
public double getAimOffset() {
36+
return offset.get();
37+
}
38+
39+
private class Shot {
40+
public double aimOffset;
41+
public double decay;
42+
public int ticksLeft;
43+
44+
public Shot(double aimOffset, double decay, int ticksLeft) {
45+
this.aimOffset = aimOffset;
46+
this.decay = decay;
47+
this.ticksLeft = ticksLeft;
48+
}
49+
50+
public double decay() {
51+
if (ticksLeft > 0) {
52+
this.aimOffset -= this.decay;
53+
this.ticksLeft --;
54+
} else {
55+
this.aimOffset = 0.0d;
56+
}
57+
return this.aimOffset;
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)