Intial Commit
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
package localmods.mtkviewpoint;
|
||||
|
||||
import java.util.*;
|
||||
import me.zed_0xff.zombie_buddy.Exposer.LuaClass;
|
||||
import se.krka.kahlua.vm.*;
|
||||
import viewpoint.core.Frame;
|
||||
import viewpoint.render.SceneData;
|
||||
import zombie.Lua.Event;
|
||||
import zombie.Lua.LuaEventManager;
|
||||
|
||||
/** Reads MTK's real projectiles on the game thread; publishes immutable render snapshots. */
|
||||
@LuaClass(name = "MTKViewpointProjectiles")
|
||||
public final class ProjectileBridge {
|
||||
static final int LIMIT = 256;
|
||||
static final double LEVEL = 2.4494895935058594;
|
||||
private static KahluaTable physics, visuals;
|
||||
private static final Map<SceneData, List<TracerMesh.Segment>> frames =
|
||||
Collections.synchronizedMap(new WeakHashMap<>());
|
||||
|
||||
private ProjectileBridge() {}
|
||||
|
||||
public static LuaClosure legacyRenderer() {
|
||||
var events = new ArrayList<Event>();
|
||||
LuaEventManager.getEvents(events, new HashMap<>());
|
||||
LuaClosure found = null;
|
||||
for (var event : events) {
|
||||
if (!"OnPreUIDraw".equals(event.name)) continue;
|
||||
for (var callback : event.callbacks) {
|
||||
var constants = Arrays.asList(callback.prototype.constants);
|
||||
if (constants.containsAll(List.of("renderline","VisualProjectilePC","currentDistance","startHeight","isCovered"))) {
|
||||
if (found != null) return null; // ambiguous: leave the dependency untouched
|
||||
found = callback;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
public static boolean bind(Object removeById, KahluaTable visualList) {
|
||||
// In installed MTK 2.0.0 removeByID closes over exactly one value:
|
||||
// projectilesByID. Read that reference; never replace or modify it.
|
||||
if (!(removeById instanceof LuaClosure fn) || fn.prototype.numParams != 2 || fn.upvalues.length != 1
|
||||
|| !Arrays.asList(fn.prototype.constants).containsAll(List.of("id","list","table","remove"))
|
||||
|| fn.upvalues[0] == null || !(fn.upvalues[0].getValue() instanceof KahluaTable table)
|
||||
|| visualList == null) return false;
|
||||
physics = table;
|
||||
visuals = visualList;
|
||||
frames.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void capture(Frame frame) {
|
||||
if (frame == null) return;
|
||||
if (physics == null || visuals == null) { frames.remove(frame.scene); return; }
|
||||
var result = new ArrayList<TracerMesh.Segment>();
|
||||
for (int i = 1, count = Math.min(visuals.len(), LIMIT); i <= count; i++) {
|
||||
if (!(visuals.rawget(i) instanceof KahluaTable visual)) continue;
|
||||
if (!(physics.rawget(visual.rawget("id")) instanceof KahluaTable shot)) continue;
|
||||
double distance = num(shot, "distance"), travelled = num(shot, "currentDistance");
|
||||
double x = num(shot,"startX"), y = num(shot,"startY"), z = num(shot,"startHeight");
|
||||
double ex = num(shot,"endX"), ey = num(shot,"endY"), ez = num(shot,"endHeight");
|
||||
if (!finite(distance,travelled,x,y,z,ex,ey,ez) || distance <= 0 || travelled <= 0 || travelled >= distance) continue;
|
||||
double scale = num(visual,"scale");
|
||||
if (!Double.isFinite(scale)) scale = 0.1;
|
||||
double length = Math.max(0.45, Math.min(2.5, distance * Math.max(0.1,scale) * 0.08));
|
||||
double head = Math.min(1,travelled/distance), tail = Math.max(0,(travelled-length)/distance);
|
||||
double hx=x+(ex-x)*head, hy=y+(ey-y)*head, hz=z+(ez-z)*head;
|
||||
double tx=x+(ex-x)*tail, ty=y+(ey-y)*tail, tz=z+(ez-z)*tail;
|
||||
float[] h=local(frame.scene,hx,hy,hz), t=local(frame.scene,tx,ty,tz);
|
||||
KahluaTable color = visual.rawget("color") instanceof KahluaTable c ? c : null;
|
||||
result.add(new TracerMesh.Segment(h[0],h[1],h[2],t[0],t[1],t[2],
|
||||
color(color,1,1),color(color,2,0.72f),color(color,3,0.14f),1));
|
||||
}
|
||||
frames.put(frame.scene,List.copyOf(result));
|
||||
}
|
||||
|
||||
static List<TracerMesh.Segment> segments(SceneData scene) {
|
||||
return frames.getOrDefault(scene,List.of());
|
||||
}
|
||||
|
||||
static float[] local(SceneData scene, double x, double y, double z) {
|
||||
double lift=scene.relief == null ? 0 : scene.relief.scene(x,y);
|
||||
return new float[]{(float)(-x-scene.originX),(float)(z*LEVEL+lift-scene.originY),(float)(-y-scene.originZ)};
|
||||
}
|
||||
|
||||
private static double num(KahluaTable t,String key) {
|
||||
return t.rawget(key) instanceof Number n ? n.doubleValue() : Double.NaN;
|
||||
}
|
||||
private static float color(KahluaTable t,int key,float fallback) {
|
||||
return t != null && t.rawget(key) instanceof Number n && Float.isFinite(n.floatValue())
|
||||
? Math.max(0,Math.min(1,n.floatValue())) : fallback;
|
||||
}
|
||||
private static boolean finite(double... values) {
|
||||
for (double v:values) if (!Double.isFinite(v)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user