User: Do you recognize the code i provided ?
```plaintext
src/com/mojang/rubydung/HitResult.java
---
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mojang.rubydung;

public class HitResult {
    public int x;
    public int y;
    public int z;
    public int o;
    public int f;

    public HitResult(int x, int y, int z, int o, int f) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.o = o;
        this.f = f;
    }
}


---
src/com/mojang/rubydung/Player.java
---
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mojang.rubydung;

import com.mojang.rubydung.level.Level;
import com.mojang.rubydung.phys.AABB;
import java.util.List;
import org.lwjgl.input.Keyboard;

public class Player {
    private Level level;
    public float xo;
    public float yo;
    public float zo;
    public float x;
    public float y;
    public float z;
    public float xd;
    public float yd;
    public float zd;
    public float yRot;
    public float xRot;
    public AABB bb;
    public boolean onGround = false;

    public Player(Level level) {
        this.level = level;
        this.resetPos();
    }

    private void resetPos() {
        float x = (float)Math.random() * (float)this.level.width;
        float y = (float)(this.level.depth + 10);
        float z = (float)Math.random() * (float)this.level.height;
        this.setPos(x, y, z);
    }

    private void setPos(float x, float y, float z) {
        this.x = x;
        this.y = y;
        this.z = z;
        float w = 0.3F;
        float h = 0.9F;
        this.bb = new AABB(x - w, y - h, z - w, x + w, y + h, z + w);
    }

    public void turn(float xo, float yo) {
        this.yRot = (float)((double)this.yRot + (double)xo * 0.15);
        this.xRot = (float)((double)this.xRot - (double)yo * 0.15);
        if (this.xRot < -90.0F) {
            this.xRot = -90.0F;
        }

        if (this.xRot > 90.0F) {
            this.xRot = 90.0F;
        }

    }

    public void tick() {
        this.xo = this.x;
        this.yo = this.y;
        this.zo = this.z;
        float xa = 0.0F;
        float ya = 0.0F;
        if (Keyboard.isKeyDown(19)) {
            this.resetPos();
        }

        if (Keyboard.isKeyDown(200) || Keyboard.isKeyDown(17)) {
            --ya;
        }

        if (Keyboard.isKeyDown(208) || Keyboard.isKeyDown(31)) {
            ++ya;
        }

        if (Keyboard.isKeyDown(203) || Keyboard.isKeyDown(30)) {
            --xa;
        }

        if (Keyboard.isKeyDown(205) || Keyboard.isKeyDown(32)) {
            ++xa;
        }

        if ((Keyboard.isKeyDown(57) || Keyboard.isKeyDown(219)) && this.onGround) {
            this.yd = 0.12F;
        }

        this.moveRelative(xa, ya, this.onGround ? 0.02F : 0.005F);
        this.yd = (float)((double)this.yd - 0.005);
        this.move(this.xd, this.yd, this.zd);
        this.xd *= 0.91F;
        this.yd *= 0.98F;
        this.zd *= 0.91F;
        if (this.onGround) {
            this.xd *= 0.8F;
            this.zd *= 0.8F;
        }

    }

    public void move(float xa, float ya, float za) {
        float xaOrg = xa;
        float yaOrg = ya;
        float zaOrg = za;
        List<AABB> aABBs = this.level.getCubes(this.bb.expand(xa, ya, za));

        for(int i = 0; i < aABBs.size(); ++i) {
            ya = ((AABB)aABBs.get(i)).clipYCollide(this.bb, ya);
        }

        this.bb.move(0.0F, ya, 0.0F);

        for(int i = 0; i < aABBs.size(); ++i) {
            xa = ((AABB)aABBs.get(i)).clipXCollide(this.bb, xa);
        }

        this.bb.move(xa, 0.0F, 0.0F);

        for(int i = 0; i < aABBs.size(); ++i) {
            za = ((AABB)aABBs.get(i)).clipZCollide(this.bb, za);
        }

        this.bb.move(0.0F, 0.0F, za);
        this.onGround = yaOrg != ya && yaOrg < 0.0F;
        if (xaOrg != xa) {
            this.xd = 0.0F;
        }

        if (yaOrg != ya) {
            this.yd = 0.0F;
        }

        if (zaOrg != za) {
            this.zd = 0.0F;
        }

        this.x = (this.bb.x0 + this.bb.x1) / 2.0F;
        this.y = this.bb.y0 + 1.62F;
        this.z = (this.bb.z0 + this.bb.z1) / 2.0F;
    }

    public void moveRelative(float xa, float za, float speed) {
        float dist = xa * xa + za * za;
        if (!(dist < 0.01F)) {
            dist = speed / (float)Math.sqrt((double)dist);
            xa *= dist;
            za *= dist;
            float sin = (float)Math.sin((double)this.yRot * Math.PI / (double)180.0F);
            float cos = (float)Math.cos((double)this.yRot * Math.PI / (double)180.0F);
            this.xd += xa * cos - za * sin;
            this.zd += za * cos + xa * sin;
        }
    }
}


---
src/com/mojang/rubydung/RubyDung.java
---
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mojang.rubydung;

import com.mojang.rubydung.level.Chunk;
import com.mojang.rubydung.level.Level;
import com.mojang.rubydung.level.LevelRenderer;
import java.awt.Component;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import javax.swing.JOptionPane;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;

public class RubyDung implements Runnable {
    private static final boolean FULLSCREEN_MODE = false;
    private int width;
    private int height;
    private FloatBuffer fogColor = BufferUtils.createFloatBuffer(4);
    private Timer timer = new Timer(60.0F);
    private Level level;
    private LevelRenderer levelRenderer;
    private Player player;
    private IntBuffer viewportBuffer = BufferUtils.createIntBuffer(16);
    private IntBuffer selectBuffer = BufferUtils.createIntBuffer(2000);
    private HitResult hitResult = null;

    public RubyDung() {
    }

    public void init() throws LWJGLException, IOException {
        int col = 920330;
        float fr = 0.5F;
        float fg = 0.8F;
        float fb = 1.0F;
        this.fogColor.put(new float[]{(float)(col >> 16 & 255) / 255.0F, (float)(col >> 8 & 255) / 255.0F, (float)(col & 255) / 255.0F, 1.0F});
        this.fogColor.flip();
        Display.setDisplayMode(new DisplayMode(1024, 768));
        Display.create();
        Keyboard.create();
        Mouse.create();
        this.width = Display.getDisplayMode().getWidth();
        this.height = Display.getDisplayMode().getHeight();
        GL11.glEnable(3553);
        GL11.glShadeModel(7425);
        GL11.glClearColor(fr, fg, fb, 0.0F);
        GL11.glClearDepth((double)1.0F);
        GL11.glEnable(2929);
        GL11.glDepthFunc(515);
        GL11.glMatrixMode(5889);
        GL11.glLoadIdentity();
        GL11.glMatrixMode(5888);
        this.level = new Level(256, 256, 64);
        this.levelRenderer = new LevelRenderer(this.level);
        this.player = new Player(this.level);
        Mouse.setGrabbed(true);
    }

    public void destroy() {
        this.level.save();
        Mouse.destroy();
        Keyboard.destroy();
        Display.destroy();
    }

    public void run() {
        try {
            this.init();
        } catch (Exception e) {
            JOptionPane.showMessageDialog((Component)null, e.toString(), "Failed to start RubyDung", 0);
            System.exit(0);
        }

        long lastTime = System.currentTimeMillis();
        int frames = 0;

        try {
            while(!Keyboard.isKeyDown(1) && !Display.isCloseRequested()) {
                this.timer.advanceTime();

                for(int i = 0; i < this.timer.ticks; ++i) {
                    this.tick();
                }

                this.render(this.timer.a);
                ++frames;

                while(System.currentTimeMillis() >= lastTime + 1000L) {
                    System.out.println(frames + " fps, " + Chunk.updates);
                    Chunk.updates = 0;
                    lastTime += 1000L;
                    frames = 0;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.destroy();
        }

    }

    public void tick() {
        this.player.tick();
    }

    private void moveCameraToPlayer(float a) {
        GL11.glTranslatef(0.0F, 0.0F, -0.3F);
        GL11.glRotatef(this.player.xRot, 1.0F, 0.0F, 0.0F);
        GL11.glRotatef(this.player.yRot, 0.0F, 1.0F, 0.0F);
        float x = this.player.xo + (this.player.x - this.player.xo) * a;
        float y = this.player.yo + (this.player.y - this.player.yo) * a;
        float z = this.player.zo + (this.player.z - this.player.zo) * a;
        GL11.glTranslatef(-x, -y, -z);
    }

    private void setupCamera(float a) {
        GL11.glMatrixMode(5889);
        GL11.glLoadIdentity();
        GLU.gluPerspective(70.0F, (float)this.width / (float)this.height, 0.05F, 1000.0F);
        GL11.glMatrixMode(5888);
        GL11.glLoadIdentity();
        this.moveCameraToPlayer(a);
    }

    private void setupPickCamera(float a, int x, int y) {
        GL11.glMatrixMode(5889);
        GL11.glLoadIdentity();
        this.viewportBuffer.clear();
        GL11.glGetInteger(2978, this.viewportBuffer);
        this.viewportBuffer.flip();
        this.viewportBuffer.limit(16);
        GLU.gluPickMatrix((float)x, (float)y, 5.0F, 5.0F, this.viewportBuffer);
        GLU.gluPerspective(70.0F, (float)this.width / (float)this.height, 0.05F, 1000.0F);
        GL11.glMatrixMode(5888);
        GL11.glLoadIdentity();
        this.moveCameraToPlayer(a);
    }

    private void pick(float a) {
        this.selectBuffer.clear();
        GL11.glSelectBuffer(this.selectBuffer);
        GL11.glRenderMode(7170);
        this.setupPickCamera(a, this.width / 2, this.height / 2);
        this.levelRenderer.pick(this.player);
        int hits = GL11.glRenderMode(7168);
        this.selectBuffer.flip();
        this.selectBuffer.limit(this.selectBuffer.capacity());
        long closest = 0L;
        int[] names = new int[10];
        int hitNameCount = 0;

        for(int i = 0; i < hits; ++i) {
            int nameCount = this.selectBuffer.get();
            long minZ = (long)this.selectBuffer.get();
            this.selectBuffer.get();
            if (minZ >= closest && i != 0) {
                for(int j = 0; j < nameCount; ++j) {
                    this.selectBuffer.get();
                }
            } else {
                closest = minZ;
                hitNameCount = nameCount;

                for(int j = 0; j < nameCount; ++j) {
                    names[j] = this.selectBuffer.get();
                }
            }
        }

        if (hitNameCount > 0) {
            this.hitResult = new HitResult(names[0], names[1], names[2], names[3], names[4]);
        } else {
            this.hitResult = null;
        }

    }

    public void render(float a) {
        float xo = (float)Mouse.getDX();
        float yo = (float)Mouse.getDY();
        this.player.turn(xo, yo);
        this.pick(a);

        while(Mouse.next()) {
            if (Mouse.getEventButton() == 1 && Mouse.getEventButtonState() && this.hitResult != null) {
                this.level.setTile(this.hitResult.x, this.hitResult.y, this.hitResult.z, 0);
            }

            if (Mouse.getEventButton() == 0 && Mouse.getEventButtonState() && this.hitResult != null) {
                int x = this.hitResult.x;
                int y = this.hitResult.y;
                int z = this.hitResult.z;
                if (this.hitResult.f == 0) {
                    --y;
                }

                if (this.hitResult.f == 1) {
                    ++y;
                }

                if (this.hitResult.f == 2) {
                    --z;
                }

                if (this.hitResult.f == 3) {
                    ++z;
                }

                if (this.hitResult.f == 4) {
                    --x;
                }

                if (this.hitResult.f == 5) {
                    ++x;
                }

                this.level.setTile(x, y, z, 1);
            }
        }

        while(Keyboard.next()) {
            if (Keyboard.getEventKey() == 28 && Keyboard.getEventKeyState()) {
                this.level.save();
            }
        }

        GL11.glClear(16640);
        this.setupCamera(a);
        GL11.glEnable(2884);
        GL11.glEnable(2912);
        GL11.glFogi(2917, 2048);
        GL11.glFogf(2914, 0.2F);
        GL11.glFog(2918, this.fogColor);
        GL11.glDisable(2912);
        this.levelRenderer.render(this.player, 0);
        GL11.glEnable(2912);
        this.levelRenderer.render(this.player, 1);
        GL11.glDisable(3553);
        if (this.hitResult != null) {
            this.levelRenderer.renderHit(this.hitResult);
        }

        GL11.glDisable(2912);
        Display.update();
    }

    public static void checkError() {
        int e = GL11.glGetError();
        if (e != 0) {
            throw new IllegalStateException(GLU.gluErrorString(e));
        }
    }

    public static void main(String[] args) throws LWJGLException {
        (new Thread(new RubyDung())).start();
    }
}


---
src/com/mojang/rubydung/Textures.java
---
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mojang.rubydung;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.HashMap;
import javax.imageio.ImageIO;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;

public class Textures {
    private static HashMap<String, Integer> idMap = new HashMap();
    private static int lastId = -9999999;

    public Textures() {
    }

    public static int loadTexture(String resourceName, int mode) {
        try {
            if (idMap.containsKey(resourceName)) {
                return (Integer)idMap.get(resourceName);
            } else {
                IntBuffer ib = BufferUtils.createIntBuffer(1);
                GL11.glGenTextures(ib);
                int id = ib.get(0);
                bind(id);
                GL11.glTexParameteri(3553, 10241, mode);
                GL11.glTexParameteri(3553, 10240, mode);
                BufferedImage img = ImageIO.read(Textures.class.getResourceAsStream(resourceName));
                int w = img.getWidth();
                int h = img.getHeight();
                ByteBuffer pixels = BufferUtils.createByteBuffer(w * h * 4);
                int[] rawPixels = new int[w * h];
                img.getRGB(0, 0, w, h, rawPixels, 0, w);

                for(int i = 0; i < rawPixels.length; ++i) {
                    int a = rawPixels[i] >> 24 & 255;
                    int r = rawPixels[i] >> 16 & 255;
                    int g = rawPixels[i] >> 8 & 255;
                    int b = rawPixels[i] & 255;
                    rawPixels[i] = a << 24 | b << 16 | g << 8 | r;
                }

                pixels.asIntBuffer().put(rawPixels);
                GLU.gluBuild2DMipmaps(3553, 6408, w, h, 6408, 5121, pixels);
                return id;
            }
        } catch (IOException var14) {
            throw new RuntimeException("!!");
        }
    }

    public static void bind(int id) {
        if (id != lastId) {
            GL11.glBindTexture(3553, id);
            lastId = id;
        }

    }
}


---
src/com/mojang/rubydung/Timer.java
---
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mojang.rubydung;

public class Timer {
    private static final long NS_PER_SECOND = 1000000000L;
    private static final long MAX_NS_PER_UPDATE = 1000000000L;
    private static final int MAX_TICKS_PER_UPDATE = 100;
    private float ticksPerSecond;
    private long lastTime;
    public int ticks;
    public float a;
    public float timeScale = 1.0F;
    public float fps = 0.0F;
    public float passedTime = 0.0F;

    public Timer(float ticksPerSecond) {
        this.ticksPerSecond = ticksPerSecond;
        this.lastTime = System.nanoTime();
    }

    public void advanceTime() {
        long now = System.nanoTime();
        long passedNs = now - this.lastTime;
        this.lastTime = now;
        if (passedNs < 0L) {
            passedNs = 0L;
        }

        if (passedNs > 1000000000L) {
            passedNs = 1000000000L;
        }

        this.fps = (float)(1000000000L / passedNs);
        this.passedTime += (float)passedNs * this.timeScale * this.ticksPerSecond / 1.0E9F;
        this.ticks = (int)this.passedTime;
        if (this.ticks > 100) {
            this.ticks = 100;
        }

        this.passedTime -= (float)this.ticks;
        this.a = this.passedTime;
    }
}


---
src/com/mojang/rubydung/level/Chunk.java
---
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mojang.rubydung.level;

import com.mojang.rubydung.Textures;
import com.mojang.rubydung.phys.AABB;
import org.lwjgl.opengl.GL11;

public class Chunk {
    public AABB aabb;
    public final Level level;
    public final int x0;
    public final int y0;
    public final int z0;
    public final int x1;
    public final int y1;
    public final int z1;
    private boolean dirty = true;
    private int lists = -1;
    private static int texture = Textures.loadTexture("/terrain.png", 9728);
    private static Tesselator t = new Tesselator();
    public static int rebuiltThisFrame = 0;
    public static int updates = 0;

    public Chunk(Level level, int x0, int y0, int z0, int x1, int y1, int z1) {
        this.level = level;
        this.x0 = x0;
        this.y0 = y0;
        this.z0 = z0;
        this.x1 = x1;
        this.y1 = y1;
        this.z1 = z1;
        this.aabb = new AABB((float)x0, (float)y0, (float)z0, (float)x1, (float)y1, (float)z1);
        this.lists = GL11.glGenLists(2);
    }

    private void rebuild(int layer) {
        if (rebuiltThisFrame != 2) {
            this.dirty = false;
            ++updates;
            ++rebuiltThisFrame;
            GL11.glNewList(this.lists + layer, 4864);
            GL11.glEnable(3553);
            GL11.glBindTexture(3553, texture);
            t.init();
            int tiles = 0;

            for(int x = this.x0; x < this.x1; ++x) {
                for(int y = this.y0; y < this.y1; ++y) {
                    for(int z = this.z0; z < this.z1; ++z) {
                        if (this.level.isTile(x, y, z)) {
                            int tex = y == this.level.depth * 2 / 3 ? 0 : 1;
                            ++tiles;
                            if (tex == 0) {
                                Tile.rock.render(t, this.level, layer, x, y, z);
                            } else {
                                Tile.grass.render(t, this.level, layer, x, y, z);
                            }
                        }
                    }
                }
            }

            t.flush();
            GL11.glDisable(3553);
            GL11.glEndList();
        }
    }

    public void render(int layer) {
        if (this.dirty) {
            this.rebuild(0);
            this.rebuild(1);
        }

        GL11.glCallList(this.lists + layer);
    }

    public void setDirty() {
        this.dirty = true;
    }
}


---
src/com/mojang/rubydung/level/Frustum.java
---
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mojang.rubydung.level;

import com.mojang.rubydung.phys.AABB;
import java.nio.FloatBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;

public class Frustum {
    public float[][] m_Frustum = new float[6][4];
    public static final int RIGHT = 0;
    public static final int LEFT = 1;
    public static final int BOTTOM = 2;
    public static final int TOP = 3;
    public static final int BACK = 4;
    public static final int FRONT = 5;
    public static final int A = 0;
    public static final int B = 1;
    public static final int C = 2;
    public static final int D = 3;
    private static Frustum frustum = new Frustum();
    private FloatBuffer _proj = BufferUtils.createFloatBuffer(16);
    private FloatBuffer _modl = BufferUtils.createFloatBuffer(16);
    private FloatBuffer _clip = BufferUtils.createFloatBuffer(16);
    float[] proj = new float[16];
    float[] modl = new float[16];
    float[] clip = new float[16];

    private Frustum() {
    }

    public static Frustum getFrustum() {
        frustum.calculateFrustum();
        return frustum;
    }

    private void normalizePlane(float[][] frustum, int side) {
        float magnitude = (float)Math.sqrt((double)(frustum[side][0] * frustum[side][0] + frustum[side][1] * frustum[side][1] + frustum[side][2] * frustum[side][2]));
        frustum[side][0] /= magnitude;
        frustum[side][1] /= magnitude;
        frustum[side][2] /= magnitude;
        frustum[side][3] /= magnitude;
    }

    private void calculateFrustum() {
        this._proj.clear();
        this._modl.clear();
        this._clip.clear();
        GL11.glGetFloat(2983, this._proj);
        GL11.glGetFloat(2982, this._modl);
        this._proj.flip().limit(16);
        this._proj.get(this.proj);
        this._modl.flip().limit(16);
        this._modl.get(this.modl);
        this.clip[0] = this.modl[0] * this.proj[0] + this.modl[1] * this.proj[4] + this.modl[2] * this.proj[8] + this.modl[3] * this.proj[12];
        this.clip[1] = this.modl[0] * this.proj[1] + this.modl[1] * this.proj[5] + this.modl[2] * this.proj[9] + this.modl[3] * this.proj[13];
        this.clip[2] = this.modl[0] * this.proj[2] + this.modl[1] * this.proj[6] + this.modl[2] * this.proj[10] + this.modl[3] * this.proj[14];
        this.clip[3] = this.modl[0] * this.proj[3] + this.modl[1] * this.proj[7] + this.modl[2] * this.proj[11] + this.modl[3] * this.proj[15];
        this.clip[4] = this.modl[4] * this.proj[0] + this.modl[5] * this.proj[4] + this.modl[6] * this.proj[8] + this.modl[7] * this.proj[12];
        this.clip[5] = this.modl[4] * this.proj[1] + this.modl[5] * this.proj[5] + this.modl[6] * this.proj[9] + this.modl[7] * this.proj[13];
        this.clip[6] = this.modl[4] * this.proj[2] + this.modl[5] * this.proj[6] + this.modl[6] * this.proj[10] + this.modl[7] * this.proj[14];
        this.clip[7] = this.modl[4] * this.proj[3] + this.modl[5] * this.proj[7] + this.modl[6] * this.proj[11] + this.modl[7] * this.proj[15];
        this.clip[8] = this.modl[8] * this.proj[0] + this.modl[9] * this.proj[4] + this.modl[10] * this.proj[8] + this.modl[11] * this.proj[12];
        this.clip[9] = this.modl[8] * this.proj[1] + this.modl[9] * this.proj[5] + this.modl[10] * this.proj[9] + this.modl[11] * this.proj[13];
        this.clip[10] = this.modl[8] * this.proj[2] + this.modl[9] * this.proj[6] + this.modl[10] * this.proj[10] + this.modl[11] * this.proj[14];
        this.clip[11] = this.modl[8] * this.proj[3] + this.modl[9] * this.proj[7] + this.modl[10] * this.proj[11] + this.modl[11] * this.proj[15];
        this.clip[12] = this.modl[12] * this.proj[0] + this.modl[13] * this.proj[4] + this.modl[14] * this.proj[8] + this.modl[15] * this.proj[12];
        this.clip[13] = this.modl[12] * this.proj[1] + this.modl[13] * this.proj[5] + this.modl[14] * this.proj[9] + this.modl[15] * this.proj[13];
        this.clip[14] = this.modl[12] * this.proj[2] + this.modl[13] * this.proj[6] + this.modl[14] * this.proj[10] + this.modl[15] * this.proj[14];
        this.clip[15] = this.modl[12] * this.proj[3] + this.modl[13] * this.proj[7] + this.modl[14] * this.proj[11] + this.modl[15] * this.proj[15];
        this.m_Frustum[0][0] = this.clip[3] - this.clip[0];
        this.m_Frustum[0][1] = this.clip[7] - this.clip[4];
        this.m_Frustum[0][2] = this.clip[11] - this.clip[8];
        this.m_Frustum[0][3] = this.clip[15] - this.clip[12];
        this.normalizePlane(this.m_Frustum, 0);
        this.m_Frustum[1][0] = this.clip[3] + this.clip[0];
        this.m_Frustum[1][1] = this.clip[7] + this.clip[4];
        this.m_Frustum[1][2] = this.clip[11] + this.clip[8];
        this.m_Frustum[1][3] = this.clip[15] + this.clip[12];
        this.normalizePlane(this.m_Frustum, 1);
        this.m_Frustum[2][0] = this.clip[3] + this.clip[1];
        this.m_Frustum[2][1] = this.clip[7] + this.clip[5];
        this.m_Frustum[2][2] = this.clip[11] + this.clip[9];
        this.m_Frustum[2][3] = this.clip[15] + this.clip[13];
        this.normalizePlane(this.m_Frustum, 2);
        this.m_Frustum[3][0] = this.clip[3] - this.clip[1];
        this.m_Frustum[3][1] = this.clip[7] - this.clip[5];
        this.m_Frustum[3][2] = this.clip[11] - this.clip[9];
        this.m_Frustum[3][3] = this.clip[15] - this.clip[13];
        this.normalizePlane(this.m_Frustum, 3);
        this.m_Frustum[4][0] = this.clip[3] - this.clip[2];
        this.m_Frustum[4][1] = this.clip[7] - this.clip[6];
        this.m_Frustum[4][2] = this.clip[11] - this.clip[10];
        this.m_Frustum[4][3] = this.clip[15] - this.clip[14];
        this.normalizePlane(this.m_Frustum, 4);
        this.m_Frustum[5][0] = this.clip[3] + this.clip[2];
        this.m_Frustum[5][1] = this.clip[7] + this.clip[6];
        this.m_Frustum[5][2] = this.clip[11] + this.clip[10];
        this.m_Frustum[5][3] = this.clip[15] + this.clip[14];
        this.normalizePlane(this.m_Frustum, 5);
    }

    public boolean pointInFrustum(float x, float y, float z) {
        for(int i = 0; i < 6; ++i) {
            if (this.m_Frustum[i][0] * x + this.m_Frustum[i][1] * y + this.m_Frustum[i][2] * z + this.m_Frustum[i][3] <= 0.0F) {
                return false;
            }
        }

        return true;
    }

    public boolean sphereInFrustum(float x, float y, float z, float radius) {
        for(int i = 0; i < 6; ++i) {
            if (this.m_Frustum[i][0] * x + this.m_Frustum[i][1] * y + this.m_Frustum[i][2] * z + this.m_Frustum[i][3] <= -radius) {
                return false;
            }
        }

        return true;
    }

    public boolean cubeFullyInFrustum(float x1, float y1, float z1, float x2, float y2, float z2) {
        for(int i = 0; i < 6; ++i) {
            if (!(this.m_Frustum[i][0] * x1 + this.m_Frustum[i][1] * y1 + this.m_Frustum[i][2] * z1 + this.m_Frustum[i][3] > 0.0F)) {
                return false;
            }

            if (!(this.m_Frustum[i][0] * x2 + this.m_Frustum[i][1] * y1 + this.m_Frustum[i][2] * z1 + this.m_Frustum[i][3] > 0.0F)) {
                return false;
            }

            if (!(this.m_Frustum[i][0] * x1 + this.m_Frustum[i][1] * y2 + this.m_Frustum[i][2] * z1 + this.m_Frustum[i][3] > 0.0F)) {
                return false;
            }

            if (!(this.m_Frustum[i][0] * x2 + this.m_Frustum[i][1] * y2 + this.m_Frustum[i][2] * z1 + this.m_Frustum[i][3] > 0.0F)) {
                return false;
            }

            if (!(this.m_Frustum[i][0] * x1 + this.m_Frustum[i][1] * y1 + this.m_Frustum[i][2] * z2 + this.m_Frustum[i][3] > 0.0F)) {
                return false;
            }

            if (!(this.m_Frustum[i][0] * x2 + this.m_Frustum[i][1] * y1 + this.m_Frustum[i][2] * z2 + this.m_Frustum[i][3] > 0.0F)) {
                return false;
            }

            if (!(this.m_Frustum[i][0] * x1 + this.m_Frustum[i][1] * y2 + this.m_Frustum[i][2] * z2 + this.m_Frustum[i][3] > 0.0F)) {
                return false;
            }

            if (!(this.m_Frustum[i][0] * x2 + this.m_Frustum[i][1] * y2 + this.m_Frustum[i][2] * z2 + this.m_Frustum[i][3] > 0.0F)) {
                return false;
            }
        }

        return true;
    }

    public boolean cubeInFrustum(float x1, float y1, float z1, float x2, float y2, float z2) {
        for(int i = 0; i < 6; ++i) {
            if (!(this.m_Frustum[i][0] * x1 + this.m_Frustum[i][1] * y1 + this.m_Frustum[i][2] * z1 + this.m_Frustum[i][3] > 0.0F) && !(this.m_Frustum[i][0] * x2 + this.m_Frustum[i][1] * y1 + this.m_Frustum[i][2] * z1 + this.m_Frustum[i][3] > 0.0F) && !(this.m_Frustum[i][0] * x1 + this.m_Frustum[i][1] * y2 + this.m_Frustum[i][2] * z1 + this.m_Frustum[i][3] > 0.0F) && !(this.m_Frustum[i][0] * x2 + this.m_Frustum[i][1] * y2 + this.m_Frustum[i][2] * z1 + this.m_Frustum[i][3] > 0.0F) && !(this.m_Frustum[i][0] * x1 + this.m_Frustum[i][1] * y1 + this.m_Frustum[i][2] * z2 + this.m_Frustum[i][3] > 0.0F) && !(this.m_Frustum[i][0] * x2 + this.m_Frustum[i][1] * y1 + this.m_Frustum[i][2] * z2 + this.m_Frustum[i][3] > 0.0F) && !(this.m_Frustum[i][0] * x1 + this.m_Frustum[i][1] * y2 + this.m_Frustum[i][2] * z2 + this.m_Frustum[i][3] > 0.0F) && !(this.m_Frustum[i][0] * x2 + this.m_Frustum[i][1] * y2 + this.m_Frustum[i][2] * z2 + this.m_Frustum[i][3] > 0.0F)) {
                return false;
            }
        }

        return true;
    }

    public boolean cubeInFrustum(AABB aabb) {
        return this.cubeInFrustum(aabb.x0, aabb.y0, aabb.z0, aabb.x1, aabb.y1, aabb.z1);
    }
}


---
src/com/mojang/rubydung/level/Level.java
---
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mojang.rubydung.level;

import com.mojang.rubydung.phys.AABB;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

public class Level {
    public final int width;
    public final int height;
    public final int depth;
    private byte[] blocks;
    private int[] lightDepths;
    private ArrayList<LevelListener> levelListeners = new ArrayList();

    public Level(int w, int h, int d) {
        this.width = w;
        this.height = h;
        this.depth = d;
        this.blocks = new byte[w * h * d];
        this.lightDepths = new int[w * h];

        for(int x = 0; x < w; ++x) {
            for(int y = 0; y < d; ++y) {
                for(int z = 0; z < h; ++z) {
                    int i = (y * this.height + z) * this.width + x;
                    this.blocks[i] = (byte)(y <= d * 2 / 3 ? 1 : 0);
                }
            }
        }

        this.calcLightDepths(0, 0, w, h);
        this.load();
    }

    public void load() {
        try {
            DataInputStream dis = new DataInputStream(new GZIPInputStream(new FileInputStream(new File("level.dat"))));
            dis.readFully(this.blocks);
            this.calcLightDepths(0, 0, this.width, this.height);

            for(int i = 0; i < this.levelListeners.size(); ++i) {
                ((LevelListener)this.levelListeners.get(i)).allChanged();
            }

            dis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void save() {
        try {
            DataOutputStream dos = new DataOutputStream(new GZIPOutputStream(new FileOutputStream(new File("level.dat"))));
            dos.write(this.blocks);
            dos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void calcLightDepths(int x0, int y0, int x1, int y1) {
        for(int x = x0; x < x0 + x1; ++x) {
            for(int z = y0; z < y0 + y1; ++z) {
                int oldDepth = this.lightDepths[x + z * this.width];

                int y;
                for(y = this.depth - 1; y > 0 && !this.isLightBlocker(x, y, z); --y) {
                }

                this.lightDepths[x + z * this.width] = y;
                if (oldDepth != y) {
                    int yl0 = oldDepth < y ? oldDepth : y;
                    int yl1 = oldDepth > y ? oldDepth : y;

                    for(int i = 0; i < this.levelListeners.size(); ++i) {
                        ((LevelListener)this.levelListeners.get(i)).lightColumnChanged(x, z, yl0, yl1);
                    }
                }
            }
        }

    }

    public void addListener(LevelListener levelListener) {
        this.levelListeners.add(levelListener);
    }

    public void removeListener(LevelListener levelListener) {
        this.levelListeners.remove(levelListener);
    }

    public boolean isTile(int x, int y, int z) {
        if (x >= 0 && y >= 0 && z >= 0 && x < this.width && y < this.depth && z < this.height) {
            return this.blocks[(y * this.height + z) * this.width + x] == 1;
        } else {
            return false;
        }
    }

    public boolean isSolidTile(int x, int y, int z) {
        return this.isTile(x, y, z);
    }

    public boolean isLightBlocker(int x, int y, int z) {
        return this.isSolidTile(x, y, z);
    }

    public ArrayList<AABB> getCubes(AABB aABB) {
        ArrayList<AABB> aABBs = new ArrayList();
        int x0 = (int)aABB.x0;
        int x1 = (int)(aABB.x1 + 1.0F);
        int y0 = (int)aABB.y0;
        int y1 = (int)(aABB.y1 + 1.0F);
        int z0 = (int)aABB.z0;
        int z1 = (int)(aABB.z1 + 1.0F);
        if (x0 < 0) {
            x0 = 0;
        }

        if (y0 < 0) {
            y0 = 0;
        }

        if (z0 < 0) {
            z0 = 0;
        }

        if (x1 > this.width) {
            x1 = this.width;
        }

        if (y1 > this.depth) {
            y1 = this.depth;
        }

        if (z1 > this.height) {
            z1 = this.height;
        }

        for(int x = x0; x < x1; ++x) {
            for(int y = y0; y < y1; ++y) {
                for(int z = z0; z < z1; ++z) {
                    if (this.isSolidTile(x, y, z)) {
                        aABBs.add(new AABB((float)x, (float)y, (float)z, (float)(x + 1), (float)(y + 1), (float)(z + 1)));
                    }
                }
            }
        }

        return aABBs;
    }

    public float getBrightness(int x, int y, int z) {
        float dark = 0.8F;
        float light = 1.0F;
        if (x >= 0 && y >= 0 && z >= 0 && x < this.width && y < this.depth && z < this.height) {
            return y < this.lightDepths[x + z * this.width] ? dark : light;
        } else {
            return light;
        }
    }

    public void setTile(int x, int y, int z, int type) {
        if (x >= 0 && y >= 0 && z >= 0 && x < this.width && y < this.depth && z < this.height) {
            this.blocks[(y * this.height + z) * this.width + x] = (byte)type;
            this.calcLightDepths(x, z, 1, 1);

            for(int i = 0; i < this.levelListeners.size(); ++i) {
                ((LevelListener)this.levelListeners.get(i)).tileChanged(x, y, z);
            }

        }
    }
}


---
src/com/mojang/rubydung/level/LevelListener.java
---
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mojang.rubydung.level;

public interface LevelListener {
    void tileChanged(int var1, int var2, int var3);

    void lightColumnChanged(int var1, int var2, int var3, int var4);

    void allChanged();
}


---
src/com/mojang/rubydung/level/LevelRenderer.java
---
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mojang.rubydung.level;

import com.mojang.rubydung.HitResult;
import com.mojang.rubydung.Player;
import com.mojang.rubydung.phys.AABB;
import org.lwjgl.opengl.GL11;

public class LevelRenderer implements LevelListener {
    private static final int CHUNK_SIZE = 16;
    private Level level;
    private Chunk[] chunks;
    private int xChunks;
    private int yChunks;
    private int zChunks;
    Tesselator t = new Tesselator();

    public LevelRenderer(Level level) {
        this.level = level;
        level.addListener(this);
        this.xChunks = level.width / 16;
        this.yChunks = level.depth / 16;
        this.zChunks = level.height / 16;
        this.chunks = new Chunk[this.xChunks * this.yChunks * this.zChunks];

        for(int x = 0; x < this.xChunks; ++x) {
            for(int y = 0; y < this.yChunks; ++y) {
                for(int z = 0; z < this.zChunks; ++z) {
                    int x0 = x * 16;
                    int y0 = y * 16;
                    int z0 = z * 16;
                    int x1 = (x + 1) * 16;
                    int y1 = (y + 1) * 16;
                    int z1 = (z + 1) * 16;
                    if (x1 > level.width) {
                        x1 = level.width;
                    }

                    if (y1 > level.depth) {
                        y1 = level.depth;
                    }

                    if (z1 > level.height) {
                        z1 = level.height;
                    }

                    this.chunks[(x + y * this.xChunks) * this.zChunks + z] = new Chunk(level, x0, y0, z0, x1, y1, z1);
                }
            }
        }

    }

    public void render(Player player, int layer) {
        Chunk.rebuiltThisFrame = 0;
        Frustum frustum = Frustum.getFrustum();

        for(int i = 0; i < this.chunks.length; ++i) {
            if (frustum.cubeInFrustum(this.chunks[i].aabb)) {
                this.chunks[i].render(layer);
            }
        }

    }

    public void pick(Player player) {
        float r = 3.0F;
        AABB box = player.bb.grow(r, r, r);
        int x0 = (int)box.x0;
        int x1 = (int)(box.x1 + 1.0F);
        int y0 = (int)box.y0;
        int y1 = (int)(box.y1 + 1.0F);
        int z0 = (int)box.z0;
        int z1 = (int)(box.z1 + 1.0F);
        GL11.glInitNames();

        for(int x = x0; x < x1; ++x) {
            GL11.glPushName(x);

            for(int y = y0; y < y1; ++y) {
                GL11.glPushName(y);

                for(int z = z0; z < z1; ++z) {
                    GL11.glPushName(z);
                    if (this.level.isSolidTile(x, y, z)) {
                        GL11.glPushName(0);

                        for(int i = 0; i < 6; ++i) {
                            GL11.glPushName(i);
                            this.t.init();
                            Tile.rock.renderFace(this.t, x, y, z, i);
                            this.t.flush();
                            GL11.glPopName();
                        }

                        GL11.glPopName();
                    }

                    GL11.glPopName();
                }

                GL11.glPopName();
            }

            GL11.glPopName();
        }

    }

    public void renderHit(HitResult h) {
        GL11.glEnable(3042);
        GL11.glBlendFunc(770, 1);
        GL11.glColor4f(1.0F, 1.0F, 1.0F, (float)Math.sin((double)System.currentTimeMillis() / (double)100.0F) * 0.2F + 0.4F);
        this.t.init();
        Tile.rock.renderFace(this.t, h.x, h.y, h.z, h.f);
        this.t.flush();
        GL11.glDisable(3042);
    }

    public void setDirty(int x0, int y0, int z0, int x1, int y1, int z1) {
        x0 /= 16;
        x1 /= 16;
        y0 /= 16;
        y1 /= 16;
        z0 /= 16;
        z1 /= 16;
        if (x0 < 0) {
            x0 = 0;
        }

        if (y0 < 0) {
            y0 = 0;
        }

        if (z0 < 0) {
            z0 = 0;
        }

        if (x1 >= this.xChunks) {
            x1 = this.xChunks - 1;
        }

        if (y1 >= this.yChunks) {
            y1 = this.yChunks - 1;
        }

        if (z1 >= this.zChunks) {
            z1 = this.zChunks - 1;
        }

        for(int x = x0; x <= x1; ++x) {
            for(int y = y0; y <= y1; ++y) {
                for(int z = z0; z <= z1; ++z) {
                    this.chunks[(x + y * this.xChunks) * this.zChunks + z].setDirty();
                }
            }
        }

    }

    public void tileChanged(int x, int y, int z) {
        this.setDirty(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1);
    }

    public void lightColumnChanged(int x, int z, int y0, int y1) {
        this.setDirty(x - 1, y0 - 1, z - 1, x + 1, y1 + 1, z + 1);
    }

    public void allChanged() {
        this.setDirty(0, 0, 0, this.level.width, this.level.depth, this.level.height);
    }
}


---
src/com/mojang/rubydung/level/Tesselator.java
---
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mojang.rubydung.level;

import java.nio.FloatBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;

public class Tesselator {
    private static final int MAX_VERTICES = 100000;
    private FloatBuffer vertexBuffer = BufferUtils.createFloatBuffer(300000);
    private FloatBuffer texCoordBuffer = BufferUtils.createFloatBuffer(200000);
    private FloatBuffer colorBuffer = BufferUtils.createFloatBuffer(300000);
    private int vertices = 0;
    private float u;
    private float v;
    private float r;
    private float g;
    private float b;
    private boolean hasColor = false;
    private boolean hasTexture = false;

    public Tesselator() {
    }

    public void flush() {
        this.vertexBuffer.flip();
        this.texCoordBuffer.flip();
        this.colorBuffer.flip();
        GL11.glVertexPointer(3, 0, this.vertexBuffer);
        if (this.hasTexture) {
            GL11.glTexCoordPointer(2, 0, this.texCoordBuffer);
        }

        if (this.hasColor) {
            GL11.glColorPointer(3, 0, this.colorBuffer);
        }

        GL11.glEnableClientState(32884);
        if (this.hasTexture) {
            GL11.glEnableClientState(32888);
        }

        if (this.hasColor) {
            GL11.glEnableClientState(32886);
        }

        GL11.glDrawArrays(7, 0, this.vertices);
        GL11.glDisableClientState(32884);
        if (this.hasTexture) {
            GL11.glDisableClientState(32888);
        }

        if (this.hasColor) {
            GL11.glDisableClientState(32886);
        }

        this.clear();
    }

    private void clear() {
        this.vertices = 0;
        this.vertexBuffer.clear();
        this.texCoordBuffer.clear();
        this.colorBuffer.clear();
    }

    public void init() {
        this.clear();
        this.hasColor = false;
        this.hasTexture = false;
    }

    public void tex(float u, float v) {
        this.hasTexture = true;
        this.u = u;
        this.v = v;
    }

    public void color(float r, float g, float b) {
        this.hasColor = true;
        this.r = r;
        this.g = g;
        this.b = b;
    }

    public void vertex(float x, float y, float z) {
        this.vertexBuffer.put(this.vertices * 3 + 0, x).put(this.vertices * 3 + 1, y).put(this.vertices * 3 + 2, z);
        if (this.hasTexture) {
            this.texCoordBuffer.put(this.vertices * 2 + 0, this.u).put(this.vertices * 2 + 1, this.v);
        }

        if (this.hasColor) {
            this.colorBuffer.put(this.vertices * 3 + 0, this.r).put(this.vertices * 3 + 1, this.g).put(this.vertices * 3 + 2, this.b);
        }

        ++this.vertices;
        if (this.vertices == 100000) {
            this.flush();
        }

    }
}


---
src/com/mojang/rubydung/level/Tile.java
---
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mojang.rubydung.level;

public class Tile {
    public static Tile rock = new Tile(0);
    public static Tile grass = new Tile(1);
    private int tex = 0;

    private Tile(int tex) {
        this.tex = tex;
    }

    public void render(Tesselator t, Level level, int layer, int x, int y, int z) {
        float u0 = (float)this.tex / 16.0F;
        float u1 = u0 + 0.0624375F;
        float v0 = 0.0F;
        float v1 = v0 + 0.0624375F;
        float c1 = 1.0F;
        float c2 = 0.8F;
        float c3 = 0.6F;
        float x0 = (float)x + 0.0F;
        float x1 = (float)x + 1.0F;
        float y0 = (float)y + 0.0F;
        float y1 = (float)y + 1.0F;
        float z0 = (float)z + 0.0F;
        float z1 = (float)z + 1.0F;
        if (!level.isSolidTile(x, y - 1, z)) {
            float br = level.getBrightness(x, y - 1, z) * c1;
            if (br == c1 ^ layer == 1) {
                t.color(br, br, br);
                t.tex(u0, v1);
                t.vertex(x0, y0, z1);
                t.tex(u0, v0);
                t.vertex(x0, y0, z0);
                t.tex(u1, v0);
                t.vertex(x1, y0, z0);
                t.tex(u1, v1);
                t.vertex(x1, y0, z1);
            }
        }

        if (!level.isSolidTile(x, y + 1, z)) {
            float br = level.getBrightness(x, y, z) * c1;
            if (br == c1 ^ layer == 1) {
                t.color(br, br, br);
                t.tex(u1, v1);
                t.vertex(x1, y1, z1);
                t.tex(u1, v0);
                t.vertex(x1, y1, z0);
                t.tex(u0, v0);
                t.vertex(x0, y1, z0);
                t.tex(u0, v1);
                t.vertex(x0, y1, z1);
            }
        }

        if (!level.isSolidTile(x, y, z - 1)) {
            float br = level.getBrightness(x, y, z - 1) * c2;
            if (br == c2 ^ layer == 1) {
                t.color(br, br, br);
                t.tex(u1, v0);
                t.vertex(x0, y1, z0);
                t.tex(u0, v0);
                t.vertex(x1, y1, z0);
                t.tex(u0, v1);
                t.vertex(x1, y0, z0);
                t.tex(u1, v1);
                t.vertex(x0, y0, z0);
            }
        }

        if (!level.isSolidTile(x, y, z + 1)) {
            float br = level.getBrightness(x, y, z + 1) * c2;
            if (br == c2 ^ layer == 1) {
                t.color(br, br, br);
                t.tex(u0, v0);
                t.vertex(x0, y1, z1);
                t.tex(u0, v1);
                t.vertex(x0, y0, z1);
                t.tex(u1, v1);
                t.vertex(x1, y0, z1);
                t.tex(u1, v0);
                t.vertex(x1, y1, z1);
            }
        }

        if (!level.isSolidTile(x - 1, y, z)) {
            float br = level.getBrightness(x - 1, y, z) * c3;
            if (br == c3 ^ layer == 1) {
                t.color(br, br, br);
                t.tex(u1, v0);
                t.vertex(x0, y1, z1);
                t.tex(u0, v0);
                t.vertex(x0, y1, z0);
                t.tex(u0, v1);
                t.vertex(x0, y0, z0);
                t.tex(u1, v1);
                t.vertex(x0, y0, z1);
            }
        }

        if (!level.isSolidTile(x + 1, y, z)) {
            float br = level.getBrightness(x + 1, y, z) * c3;
            if (br == c3 ^ layer == 1) {
                t.color(br, br, br);
                t.tex(u0, v1);
                t.vertex(x1, y0, z1);
                t.tex(u1, v1);
                t.vertex(x1, y0, z0);
                t.tex(u1, v0);
                t.vertex(x1, y1, z0);
                t.tex(u0, v0);
                t.vertex(x1, y1, z1);
            }
        }

    }

    public void renderFace(Tesselator t, int x, int y, int z, int face) {
        float x0 = (float)x + 0.0F;
        float x1 = (float)x + 1.0F;
        float y0 = (float)y + 0.0F;
        float y1 = (float)y + 1.0F;
        float z0 = (float)z + 0.0F;
        float z1 = (float)z + 1.0F;
        if (face == 0) {
            t.vertex(x0, y0, z1);
            t.vertex(x0, y0, z0);
            t.vertex(x1, y0, z0);
            t.vertex(x1, y0, z1);
        }

        if (face == 1) {
            t.vertex(x1, y1, z1);
            t.vertex(x1, y1, z0);
            t.vertex(x0, y1, z0);
            t.vertex(x0, y1, z1);
        }

        if (face == 2) {
            t.vertex(x0, y1, z0);
            t.vertex(x1, y1, z0);
            t.vertex(x1, y0, z0);
            t.vertex(x0, y0, z0);
        }

        if (face == 3) {
            t.vertex(x0, y1, z1);
            t.vertex(x0, y0, z1);
            t.vertex(x1, y0, z1);
            t.vertex(x1, y1, z1);
        }

        if (face == 4) {
            t.vertex(x0, y1, z1);
            t.vertex(x0, y1, z0);
            t.vertex(x0, y0, z0);
            t.vertex(x0, y0, z1);
        }

        if (face == 5) {
            t.vertex(x1, y0, z1);
            t.vertex(x1, y0, z0);
            t.vertex(x1, y1, z0);
            t.vertex(x1, y1, z1);
        }

    }
}


---
src/com/mojang/rubydung/phys/AABB.java
---
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mojang.rubydung.phys;

public class AABB {
    private float epsilon = 0.0F;
    public float x0;
    public float y0;
    public float z0;
    public float x1;
    public float y1;
    public float z1;

    public AABB(float x0, float y0, float z0, float x1, float y1, float z1) {
        this.x0 = x0;
        this.y0 = y0;
        this.z0 = z0;
        this.x1 = x1;
        this.y1 = y1;
        this.z1 = z1;
    }

    public AABB expand(float xa, float ya, float za) {
        float _x0 = this.x0;
        float _y0 = this.y0;
        float _z0 = this.z0;
        float _x1 = this.x1;
        float _y1 = this.y1;
        float _z1 = this.z1;
        if (xa < 0.0F) {
            _x0 += xa;
        }

        if (xa > 0.0F) {
            _x1 += xa;
        }

        if (ya < 0.0F) {
            _y0 += ya;
        }

        if (ya > 0.0F) {
            _y1 += ya;
        }

        if (za < 0.0F) {
            _z0 += za;
        }

        if (za > 0.0F) {
            _z1 += za;
        }

        return new AABB(_x0, _y0, _z0, _x1, _y1, _z1);
    }

    public AABB grow(float xa, float ya, float za) {
        float _x0 = this.x0 - xa;
        float _y0 = this.y0 - ya;
        float _z0 = this.z0 - za;
        float _x1 = this.x1 + xa;
        float _y1 = this.y1 + ya;
        float _z1 = this.z1 + za;
        return new AABB(_x0, _y0, _z0, _x1, _y1, _z1);
    }

    public float clipXCollide(AABB c, float xa) {
        if (!(c.y1 <= this.y0) && !(c.y0 >= this.y1)) {
            if (!(c.z1 <= this.z0) && !(c.z0 >= this.z1)) {
                if (xa > 0.0F && c.x1 <= this.x0) {
                    float max = this.x0 - c.x1 - this.epsilon;
                    if (max < xa) {
                        xa = max;
                    }
                }

                if (xa < 0.0F && c.x0 >= this.x1) {
                    float max = this.x1 - c.x0 + this.epsilon;
                    if (max > xa) {
                        xa = max;
                    }
                }

                return xa;
            } else {
                return xa;
            }
        } else {
            return xa;
        }
    }

    public float clipYCollide(AABB c, float ya) {
        if (!(c.x1 <= this.x0) && !(c.x0 >= this.x1)) {
            if (!(c.z1 <= this.z0) && !(c.z0 >= this.z1)) {
                if (ya > 0.0F && c.y1 <= this.y0) {
                    float max = this.y0 - c.y1 - this.epsilon;
                    if (max < ya) {
                        ya = max;
                    }
                }

                if (ya < 0.0F && c.y0 >= this.y1) {
                    float max = this.y1 - c.y0 + this.epsilon;
                    if (max > ya) {
                        ya = max;
                    }
                }

                return ya;
            } else {
                return ya;
            }
        } else {
            return ya;
        }
    }

    public float clipZCollide(AABB c, float za) {
        if (!(c.x1 <= this.x0) && !(c.x0 >= this.x1)) {
            if (!(c.y1 <= this.y0) && !(c.y0 >= this.y1)) {
                if (za > 0.0F && c.z1 <= this.z0) {
                    float max = this.z0 - c.z1 - this.epsilon;
                    if (max < za) {
                        za = max;
                    }
                }

                if (za < 0.0F && c.z0 >= this.z1) {
                    float max = this.z1 - c.z0 + this.epsilon;
                    if (max > za) {
                        za = max;
                    }
                }

                return za;
            } else {
                return za;
            }
        } else {
            return za;
        }
    }

    public boolean intersects(AABB c) {
        if (!(c.x1 <= this.x0) && !(c.x0 >= this.x1)) {
            if (!(c.y1 <= this.y0) && !(c.y0 >= this.y1)) {
                return !(c.z1 <= this.z0) && !(c.z0 >= this.z1);
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    public void move(float xa, float ya, float za) {
        this.x0 += xa;
        this.y0 += ya;
        this.z0 += za;
        this.x1 += xa;
        this.y1 += ya;
        this.z1 += za;
    }
}


---

```
Assistant: Yes, the code you've provided appears to be the source code for a simple voxel-based game, reminiscent of classic Minecraft-style games. The code is structured in Java and utilizes the Lightweight Java Game Library (LWJGL) for rendering and input handling.

Here are some key components of the code:

1. **HitResult Class**: Represents the result of a hit detection, storing the coordinates and face of the block hit.

2. **Player Class**: Manages the player's position, movement, and rotation. It handles keyboard input for movement and jumping.

3. **RubyDung Class**: The main class that initializes the game, sets up the display, and runs the game loop. It handles rendering and updating the game state.

4. **Textures Class**: Manages loading and binding textures for rendering.

5. **Level and Chunk Classes**: These classes manage the world and its structure, including loading and saving the level data. The chunks represent sections of the world, and they are rendered based on visibility.

6. **Tile Class**: Represents different types of blocks (tiles) in the game world, such as rock and grass.

7. **AABB Class**: Represents an axis-aligned bounding box used for collision detection.

8. **Frustum Class**: Implements frustum culling to determine which objects are visible in the camera's view.

9. **Tesselator Class**: Handles the batching of vertex data for rendering.

10. **LevelListener Interface**: Provides a way for different parts of the game to listen for changes in the level, such as tile changes.

This code is a good example of how to create a basic 3D game engine using Java and LWJGL, focusing on rendering, collision detection, and player interaction in a voxel environment. If you have specific questions about any part of the code or its functionality, feel free to ask!
User: The code i provided is written using Java 1.8 and LWJGL 2.9.0 , so its not new / up to date. can you help me start rewriting the code using latest version of Java 23 and LWJGL 3.3.5. lets start very small and with the basics and then gradually move on. which class should we start with first , RubyDung class maybe ?
Assistant: Certainly! Rewriting the code to use the latest versions of Java and LWJGL is a great way to modernize the project. Starting with the `RubyDung` class is a good choice, as it serves as the entry point for the application and manages the game loop and initialization.

### Steps to Rewrite the `RubyDung` Class

1. **Set Up Your Project**: Ensure you have a Java 23 environment set up and that you include LWJGL 3.3.5 in your project dependencies. You can use a build tool like Maven or Gradle to manage dependencies easily.

2. **Create the Basic Structure**: Start by creating a new Java class for `RubyDung`. Here’s a minimal version of the class, focusing on the initialization and game loop.

### Example of the RubyDung Class in Java 23 with LWJGL 3.3.5

```java
package com.mojang.rubydung;

import org.lwjgl.*;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.*;

import java.nio.*;

import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryStack.*;
import static org.lwjgl.system.MemoryUtil.*;

public class RubyDung {

    private long window;

    public void run() {
        init();
        loop();

        // Free the window callbacks and destroy the window
        glfwFreeCallbacks(window);
        glfwDestroyWindow(window);
        glfwTerminate();
        glfwSetErrorCallback(null).free();
    }

    private void init() {
        // Setup an error callback
        GLFWErrorCallback.createPrint(System.err).set();

        // Initialize GLFW
        if (!glfwInit())
            throw new IllegalStateException("Unable to initialize GLFW");

        // Configure GLFW
        glfwDefaultWindowHints();
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);

        // Create the window
        window = glfwCreateWindow(1024, 768, "RubyDung", NULL, NULL);
        if (window == NULL)
            throw new RuntimeException("Failed to create the GLFW window");

        // Center the window
        try (MemoryStack stack = stackPush()) {
            IntBuffer pWidth = stack.mallocInt(1);
            IntBuffer pHeight = stack.mallocInt(1);

            glfwGetWindowSize(window, pWidth, pHeight);

            GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor());

            glfwSetWindowPos(window, (vidMode.width() - pWidth.get(0)) / 2, (vidMode.height() - pHeight.get(0)) / 2);
        }

        // Make the OpenGL context current
        glfwMakeContextCurrent(window);
        // Enable v-sync
        glfwSwapInterval(1);

        // Make the window visible
        glfwShowWindow(window);

        // Initialize OpenGL
        GL.createCapabilities();
    }

    private void loop() {
        // Run the rendering loop until the user has attempted to close the window
        while (!glfwWindowShouldClose(window)) {
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the framebuffer

            // Swap the color buffers
            glfwSwapBuffers(window);

            // Poll for window events
            glfwPollEvents();
        }
    }

    public static void main(String[] args) {
        new RubyDung().run();
    }
}
```

### Explanation of the Code:

- **Initialization**: The `init` method sets up GLFW and creates a window. It also centers the window on the screen.
- **Game Loop**: The `loop` method contains the main game loop where rendering happens. It clears the screen and swaps the buffers to display the rendered content.
- **Main Method**: The `main` method is the entry point of the application.

### Next Steps:

1. **Run the Basic Window**: Compile and run this code to ensure that you can create a window using LWJGL 3.3.5.
2. **Add Basic Rendering**: Once the window is working, we can start adding basic rendering capabilities (like drawing a simple triangle or clearing the screen with a color).
3. **Integrate Other Classes**: After establishing the rendering, we can begin integrating other classes like `Player`, `Level`, and so on.

Let me know when you're ready to move on to the next step or if you have any questions about this initial setup!
User: can you start even simpler im new to java.
Assistant: