package com.maceswinger.client;
import static org.lwjgl.opengl.GL11.GL_BLEND;
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_ONE;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL11.glBlendFunc;
import static org.lwjgl.opengl.GL11.glClear;
import static org.lwjgl.opengl.GL11.glClearColor;
import static org.lwjgl.opengl.GL11.glColor3f;
import static org.lwjgl.opengl.GL11.glEnable;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glPopMatrix;
import static org.lwjgl.opengl.GL11.glPushMatrix;
import static org.lwjgl.opengl.GL11.glVertex2f;
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
import static org.lwjgl.opengl.GL20.glUniform1f;
import static org.lwjgl.opengl.GL20.glUniform1i;
import static org.lwjgl.opengl.GL20.glUniform2f;
import static org.lwjgl.opengl.GL20.glUniform3f;
import static org.lwjgl.opengl.GL20.glUseProgram;
import java.awt.Canvas;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import javax.net.ssl.HttpsURLConnection;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.openal.AL;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Vector2f;
import org.magnos.entity.Entity;
import org.magnos.entity.EntityList;
import com.esotericsoftware.kryonet.Client;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.FrameworkMessage;
import com.esotericsoftware.kryonet.Listener;
import com.maceswinger.Components;
import com.maceswinger.Vector2;
import com.maceswinger.client.render.SpriteRenderer;
import com.maceswinger.client.render.lighting.Block;
import com.maceswinger.client.render.lighting.Intersect;
import com.maceswinger.client.render.lighting.Light;
import com.maceswinger.client.render.lighting.Point;
import com.maceswinger.client.render.lighting.Ray;
import com.maceswinger.client.render.lighting.Wall;
import com.maceswinger.gui.Gui;
import com.maceswinger.gui.GuiMainMenu;
import com.maceswinger.mods.ModuleLoader;
import com.maceswinger.net.KryoReg;
import com.maceswinger.net.Message;
import com.maceswinger.net.ServerShell;
import com.maceswinger.server.GameServer;
import com.maceswinger.utils.CustomDisplay;
import com.maceswinger.utils.CustomMouse;
import com.maceswinger.utils.ShaderLoader;
import com.maceswinger.utils.Sound;
import com.maceswinger.utils.Textures;
import com.moomoohk.Mootilities.OSUtils.OSUtils;
/**
*
* @since Feb 4, 2014
*/
public class GameClient {
/**
*
*/
private static final long serialVersionUID = 1L;
public EntityList entities = new EntityList();
private int fps;
private static boolean fullscreen;
private static boolean VSync;
public static final float width = 1920 / 2, height = 1080 / 2;
private Gui HUD;
private Gui gui;
public static JFrame frame;
public static Canvas canvas;
public ArrayList<Light> lights = new ArrayList<Light>();
public ArrayList<Block> blocks = new ArrayList<Block>();
private Comparator<Intersect> sortIntersect = new Comparator<Intersect>() {
public int compare(Intersect n0, Intersect n1) {
if (n1.angle < n0.angle)
return 1;
if (n1.angle > n0.angle)
return -1;
return 0;
}
};
private int lightProgram;
final GameServer internalServer = new GameServer(new ServerShell() {
public void clientDisconnected(com.maceswinger.server.Client c) {
System.out.println(c.getUsername() + " disconnected");
}
public void clientConnected(com.maceswinger.server.Client c) {
System.out.println(c.getUsername() + " connected");
}
public void serverStarted(int port) {
System.out.println("Server started " + port);
}
public void serverStopped() {
System.out.println("Server stopped");
}
public void message(com.maceswinger.server.Client c, String message) {
System.out.println(c.getUsername() + ": " + message);
}
public void portInUse(int port) {
System.out.println("Unable to lock port: " + port
+ ", is another server running?");
}
});
private Client client;
public int ticks;
public boolean isGamePaused = false;
public void run() throws LWJGLException {
// fullscreen=true;
canvas = new Canvas();
frame = new JFrame();
new CustomDisplay().create(fullscreen);
AL.create();
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, width, 0, height, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_BLEND);
glEnable(GL11.GL_STENCIL_TEST);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
init();
long lastTime = System.nanoTime();
double nsPerTick = 1000000000D / 60D;
int framesPS = 0;
long lastTimer = System.currentTimeMillis();
double delta = 0;
while (!Display.isCloseRequested()) {
long now = System.nanoTime();
delta += (now - lastTime) / nsPerTick;
lastTime = now;
boolean shouldRender = true;
while (delta >= 1) {
if (Keyboard.isKeyDown(Keyboard.KEY_LMENU)
&& Keyboard.isKeyDown(Keyboard.KEY_F4))
break;
tick();
delta -= 1;
shouldRender = true;
}
render();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (shouldRender) {
framesPS++;
update();
}
if (System.currentTimeMillis() - lastTimer >= 1000) {
lastTimer += 1000;
fps = framesPS;
framesPS = 0;
}
}
internalServer.stop();
client.stop();
exit(0);
}
private void tick() {
//System.out.println(fps);
if (!Sound.isPlaying[1] && Keyboard.isKeyDown(Keyboard.KEY_P))
Sound.play(1, 1);
if (Sound.isPlaying[1] && Keyboard.isKeyDown(Keyboard.KEY_O))
Sound.pause(1, 1);
if (!isGamePaused) {
ticks++;
if (gui != null) {
gui.tick(ticks);
if (gui != null && !gui.pausesGame()) {
tickLevel();
}
} else {
tickLevel();
}
}
}
private void tickLevel() {
entities.update(this);
}
private void render() {
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, 0);
glClearColor(0, 0, 0, 1);
float x = SpriteRenderer.mainCamera.x;
float y = SpriteRenderer.mainCamera.y;
glPushMatrix();
GL11.glTranslatef(-x, -y, 0);
blocks.clear();
for (int i = 0; i < entities.size(); i++) {
Entity e = entities.at(i);
if (e.has(Components.block) && e.has(Components.position)) {
Vector2 pos = e.get(Components.position);
// if(pos.x>-SpriteRenderer.mainCamera.x+200)continue;// TODO add something so only close entities are used
// if(pos.y>-SpriteRenderer.mainCamera.y+200)continue;
// if(pos.x<-SpriteRenderer.mainCamera.x-200)continue;
// if(pos.y<-SpriteRenderer.mainCamera.y-200)continue;
Block block = e.get(Components.block);
block.x = (int) e.get(Components.position).x;
block.y = (int) e.get(Components.position).y;
blocks.add(block);
}
}
int n = 0;
for (Light light : lights) {
if (n == 0)
light.location.set(new Vector2f(CustomMouse.getX()+x, CustomMouse
.getY()+y));
n++;
light.clear();
for (Block block : blocks) {
Vector2f[] vertices = block.getVertices();
light.walls.add(new Wall(new Point(vertices[0], 0, 0),
new Point(vertices[1], 0, 0)));
light.walls.add(new Wall(new Point(vertices[1], 0, 0),
new Point(vertices[2], 0, 0)));
light.walls.add(new Wall(new Point(vertices[2], 0, 0),
new Point(vertices[3], 0, 0)));
light.walls.add(new Wall(new Point(vertices[3], 0, 0),
new Point(vertices[0], 0, 0)));
}
light.walls.add(new Wall(new Point(new Vector2f(width-x,height-y), 0, 0),
new Point(new Vector2f(width-x, height+y), 0, 0)));
light.walls.add(new Wall(new Point(new Vector2f(0, height), 0, 0),
new Point(new Vector2f(width+x, height+y), 0, 0)));
light.walls.add(new Wall(new Point(new Vector2f(width+x, height+y), 0,
0), new Point(new Vector2f(width+x, height-y), 0, 0)));
light.walls.add(new Wall(new Point(new Vector2f(width+x, height-y), 0, 0),
new Point(new Vector2f(width-x, height-y), 0, 0)));
for (Wall wall : light.walls) {
light.points.add(new Point(wall.start.pos, 0, 0));
}
for (Point point : light.points) {
float angle = (float) Math.atan2(
point.pos.y - light.location.y, point.pos.x
- light.location.x);
point.angle = angle;
light.angles.add(angle - 0.0005f);
light.angles.add(angle);
light.angles.add(angle + 0.0005f);
}
for (float angle : light.angles) {
float dx = (float) Math.cos(angle);
float dy = (float) Math.sin(angle);
Ray r = new Ray(light.location, new Vector2f(light.location.x
+ dx, light.location.y + dy));
Intersect closestIntersect = null;
for (Wall wall : light.walls) {
Intersect intersect = getIntersection(r, wall);
if (intersect == null)
continue;
if (closestIntersect == null
|| intersect.distance < closestIntersect.distance) {
closestIntersect = intersect;
}
}
if (closestIntersect == null)
continue;
closestIntersect.angle = angle;
light.intersects.add(closestIntersect);
}
Collections.sort(light.intersects, sortIntersect);
}
for (Light light : lights) {
glUseProgram(lightProgram);
glUniform2f(glGetUniformLocation(lightProgram, "lightLocation"),
(light.location.getX() - x) / CustomDisplay.getxScale(),
(light.location.getY() - y) / CustomDisplay.getyScale());
glUniform3f(glGetUniformLocation(lightProgram, "lightColor"),
light.red, light.green, light.blue);
glUniform1f(glGetUniformLocation(lightProgram, "lightRadius"),
light.radius);
glBindTexture(GL_TEXTURE_2D,Textures.textureID[0]);
glUniform1i(glGetUniformLocation(lightProgram, "lookup"), 0);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glColor3f(1, 0, 1);
glBegin(GL11.GL_TRIANGLE_STRIP);
for (Intersect i : light.intersects) {
glVertex2f(i.pos.x, i.pos.y);
glVertex2f(light.location.x, light.location.y);
}
Intersect i = light.intersects.get(0);
glVertex2f(i.pos.x, i.pos.y);
glEnd();
}
glUseProgram(0);
glColor3f(1, 1, 1);
glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
entities.draw(null);
glPopMatrix();
if (HUD != null)
HUD.render();
if (gui != null)
gui.render();
}
private Intersect getIntersection(Ray ray, Wall segment) {
// RAY in parametric: Point + Delta*T1
float r_px = ray.start.x;
float r_py = ray.start.y;
float r_dx = ray.end.x - ray.start.x;
float r_dy = ray.end.y - ray.start.y;
// SEGMENT in parametric: Point + Delta*T2
float s_px = segment.start.pos.x;
float s_py = segment.start.pos.y;
float s_dx = segment.end.pos.x - segment.start.pos.x;
float s_dy = segment.end.pos.y - segment.start.pos.y;
// Are they parallel? If so, no intersect
float r_mag = (float) Math.sqrt(r_dx * r_dx + r_dy * r_dy);
float s_mag = (float) Math.sqrt(s_dx * s_dx + s_dy * s_dy);
if (r_dx / r_mag == s_dx / s_mag && r_dy / r_mag == s_dy / s_mag) {
// Unit vectors are the same.
return null;
}
// SOLVE FOR T1 & T2
// r_px+r_dx*T1 = s_px+s_dx*T2 && r_py+r_dy*T1 = s_py+s_dy*T2
// ==> T1 = (s_px+s_dx*T2-r_px)/r_dx = (s_py+s_dy*T2-r_py)/r_dy
// ==> s_px*r_dy + s_dx*T2*r_dy - r_px*r_dy = s_py*r_dx + s_dy*T2*r_dx -
// r_py*r_dx
// ==> T2 = (r_dx*(s_py-r_py) + r_dy*(r_px-s_px))/(s_dx*r_dy -
// s_dy*r_dx)
float T2 = (r_dx * (s_py - r_py) + r_dy * (r_px - s_px))
/ (s_dx * r_dy - s_dy * r_dx);
float T1 = (s_px + s_dx * T2 - r_px) / r_dx;
// Must be within parametic whatevers for RAY/SEGMENT
if (T1 < 0)
return null;
if (T2 < 0 || T2 > 1)
return null;
// Return the POINT OF INTERSECTION
return new Intersect(new Vector2f(r_px + r_dx * T1, r_py + r_dy * T1),
T1, 0);
}
private void update() {
if (!fullscreen)
resize(canvas.getWidth(), canvas.getHeight());
if (VSync)
Display.sync(60);
Display.update();
}
private void resize(int i, int j) {
GL11.glViewport(0, 0, i, j);
CustomDisplay.setyScale(GameClient.height / Display.getHeight());
CustomDisplay.setxScale(GameClient.width / Display.getWidth());
}
private void init() {
SpriteRenderer.mainCamera = new Vector2();
System.out.println("Loading!");
long startTime = System.currentTimeMillis();
Sound.loadSounds();
Textures.loadAll();
ModuleLoader.initMods();
ModuleLoader.debugPasteCoreMod();
setUpShaders();
long endTime = System.currentTimeMillis();
long time = endTime - startTime;
System.out.println("Loaded in: " + time + " ms");
gui = new GuiMainMenu(this, (int) width, (int) height);
}
private void setUpShaders() {
lightProgram = ShaderLoader.loadShaderPair("rsc/shader.vs",
"rsc/shader.frag");
}
public void closeGui() {
this.gui = null;
}
/**
* Must be the exit route of the game
*
* @param code
* - Exit code
*/
public static void exit(int code) {
switch (code) {
case 0:
System.out.println("System exiting normally");
long startTime = System.currentTimeMillis();
Textures.deleteAll();
Sound.deleteSounds();
AL.destroy();
Display.destroy();
long endTime = System.currentTimeMillis();
long time = endTime - startTime;
System.out.println("Exited in: " + time + " ms");
System.exit(0);
break;
case 1:
System.err.println("Exciting due to error!");
long startTime1 = System.currentTimeMillis();
Textures.deleteAll();
Sound.deleteSounds();
AL.destroy();
Display.destroy();
long endTime1 = System.currentTimeMillis();
long time1 = endTime1 - startTime1;
System.out.println("Exited in: " + time1 + " ms");
System.exit(0);
break;
}
}
public void startGame() {
for (int i = 1; i <= 1; i++) {
Vector2f location = new Vector2f((float) Math.random() * width,
(float) Math.random() * height);
lights.add(new Light(location, 20, 1,
1, 1));
}
new Thread(new Runnable() {
@Override
public void run() {
internalServer.run(2650);
}
}, "Internal server thread").start();
client = new Client();
KryoReg.reg(client.getKryo());
client.start();
client.addListener(new Listener.LagListener(50, 100, new Listener() {
@Override
public void received(Connection connection, Object o) {
if (o.getClass() != FrameworkMessage.keepAlive.getClass()
&& o instanceof Message)
((Message) o).runClient(GameClient.this);
}
}));
try {
client.connect(5000, "localhost", 2650); // Where you'd put an ip
} catch (IOException e1) {
e1.printStackTrace();
}
}
public static String connect(String php, String[] keys, String[] values)
throws Exception {
String charset = "UTF-8";
String query = "?";
if (keys != null && values != null) {
if (keys.length != values.length)
throw new IllegalArgumentException("Keys length ("
+ keys.length + ") != values length (" + values.length
+ ")");
for (int i = 0; i < keys.length; i++)
query += String.format(keys[i] + "=%s",
URLEncoder.encode(values[i], charset));
}
HttpsURLConnection connection = (HttpsURLConnection) new URL(
"https://maceswinger.com/utils/" + php + ".php" + query)
.openConnection();
connection.setDoOutput(true);
connection.setConnectTimeout(15 * 1000);
connection.setReadTimeout(15 * 1000);
connection.setRequestProperty("Accept-Charset", charset);
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded;charset=" + charset);
connection.setRequestProperty("User-Agent",
"Mace Swinger Launcher/1.0 ("
+ OSUtils.getCurrentOS().toString() + ")");
connection.setRequestMethod("POST");
BufferedReader in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String inputLine;
final StringBuilder inputLines = new StringBuilder("");
while ((inputLine = in.readLine()) != null)
inputLines.append(inputLine.trim() + "\n");
in.close();
connection.disconnect();
return inputLines.toString().trim();
}
public static void main(String[] args) {
// try
// {
// HashMap<String, String> flags = CommandsManager.parseFlags(args);
// if ((flags.containsKey("online") &&
// flags.get("online").equals("true") && !flags.containsKey("sid")) ||
// (flags.containsKey("sid") && !flags.containsKey("online")))
// {
// System.out.println("Please use the Mace Swinger Launcher to launch the game.");
// JOptionPane.showMessageDialog(null,
// "Please use the Mace Swinger Launcher to launch the game.", "",
// JOptionPane.PLAIN_MESSAGE);
// return;
// }
// if (flags.get("online").equals("true"))
// {
// String sessinfo = connect("sessinfo", new String[] { "sid" }, new
// String[] { flags.get("sid") });
// Scanner s = new Scanner(sessinfo);
// s.useDelimiter(":");
// boolean valid = s.hasNextLine() && s.nextBoolean();
// if (!valid || valid && s.nextInt() == 0)
// {
// System.out.println("Invalid session ID. Please login and launch the game through the launcher.");
// JOptionPane.showMessageDialog(null,
// "Invalid session ID. Please login and launch the game through the launcher.",
// "", JOptionPane.PLAIN_MESSAGE);
// return;
// }
// }
//
// JOptionPane.showMessageDialog(null, "this is gaem", "",
// JOptionPane.PLAIN_MESSAGE);
// //System.exit(0);
//
// fullscreen = flags.get("fullscreen").equals("true");
// //VSync = flags.get("vsync").equals("true");
// }
// catch (Exception e)
// {
// return;
// }
try {
System.setProperty("org.lwjgl.librarypath",
OSUtils.getDynamicStorageLocation() + "Mace Swinger"
+ File.separator + "lwjgl" + File.separator
+ OSUtils.getCurrentOS().toString().toLowerCase());
System.setProperty("net.java.games.input.librarypath",
System.getProperty("org.lwjgl.librarypath"));
} catch (UnsatisfiedLinkError e) {
System.out
.println("LWJGL natives not found! Please use the launcher to download them.");
JOptionPane
.showMessageDialog(
null,
"LWJGL natives not found! Please use the launcher to download them.",
"", JOptionPane.PLAIN_MESSAGE);
return;
}
try {
new GameClient().run();
} catch (LWJGLException e) {
e.printStackTrace();
}
}
}