浏览代码

Trying to do perspective projection, but it generates levels that crashes the game. (WTF new exploit ?)

____tbvns____ 5 月之前
父节点
当前提交
c50f63b383

+ 7 - 0
GD4J/src/main/java/xyz/tbvns/GDConstant.java

@@ -12,4 +12,11 @@ public class GDConstant {
     public static final int FAST_SPEED_OBJECT_ID = 202;
     public static final int FAST_SPEED_OBJECT_ID = 202;
     public static final int FASTER_SPEED_OBJECT_ID = 203;
     public static final int FASTER_SPEED_OBJECT_ID = 203;
     public static final int FASTEST_SPEED_OBJECT_ID = 1334;
     public static final int FASTEST_SPEED_OBJECT_ID = 1334;
+
+    public static final int X_PROPERTY_ID = 2;
+    public static final int Y_PROPERTY_ID = 3;
+    public static final int Z_LAYER_PROPERTY_ID = 24;
+    public static final int EDITOR_LAYER_PROPERTY_ID = 20;
+
+    public static final int POINT_OBJECT_ID = 725;
 }
 }

+ 49 - 0
GD4J/src/main/java/xyz/tbvns/LevelStringBuilder.java

@@ -0,0 +1,49 @@
+package xyz.tbvns;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.HashMap;
+
+import static xyz.tbvns.GDConstant.EDITOR_LAYER_PROPERTY_ID;
+
+@NoArgsConstructor
+@AllArgsConstructor
+public class LevelStringBuilder {
+    @Getter
+    private String levelString = "";
+    @Getter @Setter
+    private int editorLayer;
+
+    public LevelStringBuilder add(double ... properties) {
+        for (double s : properties) {
+            levelString += s + ",";
+        }
+        if (editorLayer != 0) {
+            levelString += EDITOR_LAYER_PROPERTY_ID + "," + editorLayer + ",";
+        }
+        levelString = removeLastChar(levelString);
+        levelString += ";";
+        return this;
+    }
+
+    public LevelStringBuilder add(HashMap<String, String> properties) {
+        properties.forEach((k, v) -> {
+            levelString += k + "," + v;
+        });
+        if (editorLayer != 0) {
+            levelString += EDITOR_LAYER_PROPERTY_ID + "," + editorLayer + ",";
+        }
+        levelString = removeLastChar(levelString);
+        levelString += ";";
+        return this;
+    }
+
+    public static String removeLastChar(String s) {
+        return (s == null || s.length() == 0)
+                ? null
+                : (s.substring(0, s.length() - 1));
+    }
+}

+ 0 - 1
GD4J/src/main/java/xyz/tbvns/XmlUtils.java

@@ -30,7 +30,6 @@ public class XmlUtils {
     }
     }
 
 
     public static String gamesheetToXML(String data) {
     public static String gamesheetToXML(String data) {
-        //TODO: Replace that with custom reader
         String[] lines = data
         String[] lines = data
                 .replace(" ", "")
                 .replace(" ", "")
                 .split("\n");
                 .split("\n");

+ 2 - 2
PowerGDEditor/src/main/java/xyz/tbvns/Editor/ModelsManager.java

@@ -30,7 +30,6 @@ public class ModelsManager {
 
 
     public static void addModel(File obj) throws FileNotFoundException {
     public static void addModel(File obj) throws FileNotFoundException {
         File mtl = new File(obj.getParent() + "/" + obj.getName().replace(".obj", ".mtl"));
         File mtl = new File(obj.getParent() + "/" + obj.getName().replace(".obj", ".mtl"));
-        System.out.println(mtl.getPath());
         if (!mtl.exists()) {
         if (!mtl.exists()) {
             throw new FileNotFoundException("Missing mtl file");
             throw new FileNotFoundException("Missing mtl file");
         }
         }
@@ -85,7 +84,8 @@ public class ModelsManager {
         selectedModelInstance.userData = new GDInstance(
         selectedModelInstance.userData = new GDInstance(
                 selectedModelInstance,
                 selectedModelInstance,
                 model.getName(),
                 model.getName(),
-                model.getName() + "-" + new Random().nextInt(0, 9999)
+                model.getName() + "-" + new Random().nextInt(0, 9999),
+                model
         );
         );
         BulletManager.addModel(selectedModelInstance);
         BulletManager.addModel(selectedModelInstance);
         loadedModels.add(selectedModelInstance);
         loadedModels.add(selectedModelInstance);

+ 107 - 0
PowerGDEditor/src/main/java/xyz/tbvns/GeometryDash/Render.java

@@ -0,0 +1,107 @@
+package xyz.tbvns.GeometryDash;
+
+import com.badlogic.gdx.graphics.g3d.ModelInstance;
+import com.badlogic.gdx.math.Vector3;
+import org.joml.Matrix4d;
+import org.joml.Vector3d;
+import org.joml.Vector4d;
+import org.joml.Vector4f;
+import xyz.tbvns.Editor.ModelsManager;
+import xyz.tbvns.GDConstant;
+import xyz.tbvns.LevelInfo;
+import xyz.tbvns.LevelStringBuilder;
+import xyz.tbvns.Models.Face;
+import xyz.tbvns.Models.GDInstance;
+import xyz.tbvns.Models.GDModel;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import static xyz.tbvns.GDConstant.*;
+
+public class Render {
+    public double currentPercent;
+    public double currentDistance;
+    public HashMap<GDInstance, Integer> animationToCurrentframe = new HashMap<>();
+    public String fullRender(double fps) {
+        LevelStringBuilder builder = new LevelStringBuilder(LevelInfo.getLevelString(), 10); //TODO: make the editor layer configurable
+        while (currentPercent <= 1) {
+            double speed = LevelInfo.getLevel().getSpeedAt((float) currentPercent);
+            double distancePerFrame = (speed / fps);
+            currentPercent += distancePerFrame;
+            double realDistancePerFrame = (speed / fps) / 30;
+            double distancePerFramePercent = realDistancePerFrame / LevelInfo.getLevel().getMaxPos();
+            currentPercent += distancePerFramePercent;
+
+            Matrix4d camera = new Matrix4d();
+            camera.perspective(Math.toRadians(2), (double) 16/9, 0.001, 1000);
+            Vector3d cameraTranslation = new Vector3d(realDistancePerFrame * currentPercent, 5, 10);
+            camera.translation(cameraTranslation); //TODO: make that follow a new camera path editor
+            builder.add(1, 1, X_PROPERTY_ID, projectPoint(camera, new Vector4f((float) cameraTranslation.x, (float) cameraTranslation.y, (float) cameraTranslation.z, 0)).x, projectPoint(camera, new Vector4f((float) cameraTranslation.x, (float) cameraTranslation.y, (float) cameraTranslation.z, 0)).y);
+
+            for (ModelInstance model : ModelsManager.getLoadedModels()) {
+                GDInstance instance = (GDInstance) model.userData;
+                if (instance.isAnimation()) {
+                    //TODO: the code under here will cause issue with the first frame being drawn at the start of the level but not the others
+                    int frame = instance.getFrameOnPercent(currentPercent);
+                    if (animationToCurrentframe.containsKey(instance) && animationToCurrentframe.get(instance) != frame) {
+                        animationToCurrentframe.put(instance, frame);
+                        GDModel gdModel = instance.getAnimationObject().getFrames().get(frame);
+                        for (Face face : gdModel.getFaces()) {
+                            for (Vector4f point : face.points) {
+                                Vector3 translation = instance.getInstance().transform.getTranslation(Vector3.Zero);
+                                point = point.add(translation.x, translation.y, translation.z, 0);
+                                Vector4d projected = projectPoint(camera, point);
+                                builder.add(1, POINT_OBJECT_ID, X_PROPERTY_ID, projected.x, Y_PROPERTY_ID, projected.y);
+                            }
+                        }
+                    } else {
+                        animationToCurrentframe.put(instance, frame);
+                    }
+                } else {
+                    GDModel gdModel = instance.getGdModel();
+                    for (Face face : gdModel.getFaces()) {
+                        for (Vector4f point : face.points) {
+                            Vector3 translation = instance.getInstance().transform.getTranslation(Vector3.Zero);
+                            point = point.add(translation.x, translation.y, translation.z, 0);
+                            Vector4d projected = projectPoint(camera, point);
+                            builder.add(1, POINT_OBJECT_ID, X_PROPERTY_ID, projected.x, Y_PROPERTY_ID, projected.y);
+                        }
+                    }
+                }
+            }
+        }
+        return builder.getLevelString();
+    }
+
+    public Vector4d projectPoint(Matrix4d camera, Vector4f input) {
+        Vector4d point = camera.transform(new Vector4d(input.x, input.y, input.z, input.w));
+
+        point.x = (float) (point.x / point.w);
+        point.y = (float) (point.y / point.w);
+        point.z = (float) (point.z / point.w);
+
+        return point;
+    }
+
+    public static float getZ(Face face) {
+        //TODO: REDO ALL OF THIS WITH MY SAVIOUR "JOML" !
+        //d = √[(x2 − x1)2 + (y2 − y1)2 + (z2 − z1)2]
+        List<Double> dist = new ArrayList<>();
+
+        face.points.forEach(p -> {
+            dist.add((double) p.w);
+        });
+
+        double temp = 0;
+
+        for (Double d : dist) {
+            temp += d;
+        }
+
+        temp = temp / dist.size();
+
+        return (float) temp;
+    }
+}

+ 5 - 0
PowerGDEditor/src/main/java/xyz/tbvns/Main.java

@@ -10,9 +10,14 @@ import com.badlogic.gdx.graphics.g3d.*;
 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
 import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
 import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
 import com.badlogic.gdx.math.Vector3;
 import com.badlogic.gdx.math.Vector3;
+import com.badlogic.gdx.math.Vector4;
 import com.badlogic.gdx.physics.bullet.Bullet;
 import com.badlogic.gdx.physics.bullet.Bullet;
 import com.badlogic.gdx.utils.viewport.Viewport;
 import com.badlogic.gdx.utils.viewport.Viewport;
 import lombok.Getter;
 import lombok.Getter;
+import org.joml.Matrix4dc;
+import org.joml.Vector3d;
+import org.joml.Vector4d;
+import org.joml.Vector4dc;
 import org.lwjgl.opengl.GL11;
 import org.lwjgl.opengl.GL11;
 import xyz.tbvns.Editor.ModelsManager;
 import xyz.tbvns.Editor.ModelsManager;
 import xyz.tbvns.Inputs.Shortcut;
 import xyz.tbvns.Inputs.Shortcut;

+ 10 - 14
PowerGDEditor/src/main/java/xyz/tbvns/Models/GDInstance.java

@@ -2,7 +2,6 @@ package xyz.tbvns.Models;
 
 
 import com.badlogic.gdx.graphics.g3d.Model;
 import com.badlogic.gdx.graphics.g3d.Model;
 import com.badlogic.gdx.graphics.g3d.ModelInstance;
 import com.badlogic.gdx.graphics.g3d.ModelInstance;
-import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.NoArgsConstructor;
 import xyz.tbvns.LevelInfo;
 import xyz.tbvns.LevelInfo;
@@ -10,11 +9,12 @@ import xyz.tbvns.LevelInfo;
 @Data
 @Data
 @NoArgsConstructor
 @NoArgsConstructor
 public class GDInstance {
 public class GDInstance {
-    public GDInstance(ModelInstance instance, String name, String id) {
+    public GDInstance(ModelInstance instance, String name, String id, GDModel gdModel) {
         this.instance = instance;
         this.instance = instance;
         this.name = name;
         this.name = name;
         this.id = id;
         this.id = id;
         this.animation = false;
         this.animation = false;
+        this.gdModel = gdModel;
     }
     }
 
 
     public GDInstance(ModelInstance instance, int fps, int frameSkip, double start, String name, String id, Animation animation) {
     public GDInstance(ModelInstance instance, int fps, int frameSkip, double start, String name, String id, Animation animation) {
@@ -26,16 +26,16 @@ public class GDInstance {
         this.id = id;
         this.id = id;
         this.animation = true;
         this.animation = true;
         this.animationObject = animation;
         this.animationObject = animation;
-        this.expanded = false;
+        this.followCamera = false;
     }
     }
 
 
     public void updateFrame(double percent) {
     public void updateFrame(double percent) {
-        instance = new ModelInstance(getFrameOnPercent(percent), instance.transform);
+        instance = new ModelInstance(animationObject.getModelFrames().get(getFrameOnPercent(percent)), instance.transform);
         instance.userData = this;
         instance.userData = this;
     }
     }
 
 
     //TODO: Make this not break if the speed change in the middle of the animation
     //TODO: Make this not break if the speed change in the middle of the animation
-    public Model getFrameOnPercent(double percent) {
+    public int getFrameOnPercent(double percent) {
         double usablePercent = percent - (start / 100);
         double usablePercent = percent - (start / 100);
         if (usablePercent > 0) {
         if (usablePercent > 0) {
             float max = LevelInfo.getLevel().getMaxPos();
             float max = LevelInfo.getLevel().getMaxPos();
@@ -45,25 +45,21 @@ public class GDInstance {
             double distancePerFrame = (speed / fps) * 10;
             double distancePerFrame = (speed / fps) * 10;
             int frame = (int) (pos / distancePerFrame);
             int frame = (int) (pos / distancePerFrame);
 
 
-            System.out.println(pos + " - " + frame);
-
-            // Ensure the frame is within bounds
             if (frame < animationObject.getModelFrames().size()) {
             if (frame < animationObject.getModelFrames().size()) {
-                return animationObject.getModelFrames().get(frame);
+                return frame;
             }
             }
-            return animationObject.getModelFrames().getLast();
+            return animationObject.getModelFrames().size() - 1;
         }
         }
-        return animationObject.getModelFrames().getFirst();
+        return 0;
     }
     }
 
 
-
     private ModelInstance instance;
     private ModelInstance instance;
     private boolean animation;
     private boolean animation;
     private double start;
     private double start;
     private int current;
     private int current;
     private int fps, frameSkip;
     private int fps, frameSkip;
-    //TODO: add keyframes
     private String name, id;
     private String name, id;
-    private boolean expanded;
+    private boolean followCamera;
     private Animation animationObject;
     private Animation animationObject;
+    private GDModel gdModel;
 }
 }

+ 0 - 6
PowerGDEditor/src/main/java/xyz/tbvns/Physics/BulletManager.java

@@ -84,12 +84,6 @@ public class BulletManager {
             object.activate(true);
             object.activate(true);
         }
         }
 
 
-        if (rayResultCallback.hasHit()) {
-            System.out.println("Hit object: " + rayResultCallback.getCollisionObject());
-        } else {
-            System.out.println("No hit detected");
-        }
-
         return rayResultCallback.getCollisionObject();
         return rayResultCallback.getCollisionObject();
     }
     }
 
 

+ 5 - 11
PowerGDEditor/src/main/java/xyz/tbvns/ui/Elements/Timeline.java

@@ -1,26 +1,19 @@
 package xyz.tbvns.ui.Elements;
 package xyz.tbvns.ui.Elements;
 
 
 import com.badlogic.gdx.Gdx;
 import com.badlogic.gdx.Gdx;
-import com.badlogic.gdx.graphics.g3d.Model;
 import com.badlogic.gdx.graphics.g3d.ModelInstance;
 import com.badlogic.gdx.graphics.g3d.ModelInstance;
 import imgui.ImGui;
 import imgui.ImGui;
-import imgui.extension.imguizmo.ImGuizmo;
 import imgui.flag.ImGuiWindowFlags;
 import imgui.flag.ImGuiWindowFlags;
 import imgui.type.ImDouble;
 import imgui.type.ImDouble;
-import imgui.type.ImFloat;
 import imgui.type.ImInt;
 import imgui.type.ImInt;
 import imgui.type.ImString;
 import imgui.type.ImString;
 import xyz.tbvns.Editor.ModelsManager;
 import xyz.tbvns.Editor.ModelsManager;
 import xyz.tbvns.LevelInfo;
 import xyz.tbvns.LevelInfo;
 import xyz.tbvns.Main;
 import xyz.tbvns.Main;
 import xyz.tbvns.Models.GDInstance;
 import xyz.tbvns.Models.GDInstance;
-import xyz.tbvns.Models.GDModel;
 import xyz.tbvns.Utils;
 import xyz.tbvns.Utils;
 import xyz.tbvns.ui.Element;
 import xyz.tbvns.ui.Element;
 
 
-import java.util.HashMap;
-import java.util.Random;
-
 public class Timeline implements Element {
 public class Timeline implements Element {
 
 
     @Override
     @Override
@@ -71,10 +64,11 @@ public class Timeline implements Element {
                 ImGui.inputDouble("##startPercent" + instance.getId(), startPercent);
                 ImGui.inputDouble("##startPercent" + instance.getId(), startPercent);
                 instance.setStart(startPercent.get());
                 instance.setStart(startPercent.get());
 
 
-                ImGui.sameLine();
-                if (ImGui.checkbox("Expand", instance.isExpanded())) {
-                    instance.setExpanded(!instance.isExpanded());
-                }
+            }
+
+            ImGui.sameLine();
+            if (ImGui.checkbox("Follow camera", instance.isFollowCamera())) {
+                instance.setFollowCamera(!instance.isFollowCamera());
             }
             }
         }
         }
 
 

+ 13 - 1
PowerGDEditor/src/main/java/xyz/tbvns/ui/MenuBarTabs/SaveMenu.java

@@ -1,6 +1,10 @@
 package xyz.tbvns.ui.MenuBarTabs;
 package xyz.tbvns.ui.MenuBarTabs;
 
 
 import imgui.ImGui;
 import imgui.ImGui;
+import xyz.tbvns.DataManager;
+import xyz.tbvns.Decoder;
+import xyz.tbvns.GeometryDash.Render;
+import xyz.tbvns.LevelInfo;
 import xyz.tbvns.Main;
 import xyz.tbvns.Main;
 import xyz.tbvns.ui.MenuBarTab;
 import xyz.tbvns.ui.MenuBarTab;
 import xyz.tbvns.ui.UIManager;
 import xyz.tbvns.ui.UIManager;
@@ -10,7 +14,15 @@ public class SaveMenu implements MenuBarTab {
     @Override
     @Override
     public void render() {
     public void render() {
         if (ImGui.beginMenu("Files")) {
         if (ImGui.beginMenu("Files")) {
-            ImGui.menuItem("Save", "CTRL S");
+            if (ImGui.menuItem("Save", "CTRL S")) {
+                try {
+                    LevelInfo.setLevelString(LevelInfo.getLevelString() + new Render().fullRender(24));
+                    LevelInfo.getLevel().setEncodedLevelString(Decoder.encodeLevel(LevelInfo.getLevelString()));
+                    DataManager.saveLevel(LevelInfo.getLevel());
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
             ImGui.menuItem("Export", "SHIFT S");
             ImGui.menuItem("Export", "SHIFT S");
             if (ImGui.menuItem("Open", "O")) {
             if (ImGui.menuItem("Open", "O")) {
                 UIManager.getActiveUI().put(LevelSelector.class, true);
                 UIManager.getActiveUI().put(LevelSelector.class, true);