package fm.ak.server;
import static fm.ak.server.Main.ui;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.nio.CharBuffer;
import java.sql.*;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import fm.ak.server.fragment.FragmentList;
import fm.ak.server.fragment.Player;
import java.net.SocketException;
public class Seat extends Thread
{
static private int sidS, hashesc = 0;
FragmentList Frags;
static int w = 1024, h = 600;
public int sid, pid;
boolean Even;
private int Lever = 0, Switch = 0, hashc;
private String Data = null;
private static CharBuffer cbuf;
private static final int[] Opposite = {2, 3, 0, 1};
private Socket client = null;
BufferedReader In = null;
DataOutputStream Out = null;
String SelfQuery;
Statement SelfSttmnt;
ResultSet SelfRow;
String Apart[];
String Values[];
String r;
Player p;
static HashMap<Integer, Seat> Bus = new HashMap<Integer, Seat>();
static HashMap<Integer, Seat> SynchronizedBus = new HashMap<Integer, Seat>();
ArrayList<Seat> Seen = new ArrayList<Seat>();
int TileRegion[] = {0, 0};
private boolean kill;
public Seat(Socket socket) throws SQLException, SocketException
{
hashc = ++ hashesc;
Even = (sid = sidS ++) % 2 == 0;
this.client = socket;
this.Frags = new FragmentList(this);
socket.setKeepAlive(true); // ?
try {
buckle();
} catch (IOException ex) {
Main.ui.commitln("Player " + sid + " couldn't connect");
kill();
Logger.getLogger(Seat.class.getName()).log(Level.SEVERE, null, ex);
}
}
final public void buckle() throws IOException
{
Main.ui.commitln("Player " + sid + " joining...");
In = new BufferedReader( new InputStreamReader( client.getInputStream() ) );
Out = new DataOutputStream( client.getOutputStream() );
ui.commitln("Player " + sid + " joined");
start();
}
final public void kill()
{
Main.ui.commitln("Player " + sid + " removed");
Bus.remove(pid);
kill = true;
}
/** All sending is done by this method.*/
synchronized void Send(String r)
{
try
{
if(r==null)return;
Lever = ( Lever == 1 ) ? 0 : 1;
Out.writeByte(Lever);
r = Frags.Write(r);
int Outlet = 1;
for(;Outlet * 127 <= r.length() + 127; Outlet ++ )
Out.writeByte( ( r.length() >= Outlet * 127 ) ? 127 : r.length() - ((Outlet-1)*127) );
if( r.length() == Outlet * 127) Out.writeByte( 0 );
Out.writeBytes( r );
//System.out.println(sid+":sent \""+r+"\"");
}
catch (IOException ex)
{
Logger.getLogger(Seat.class.getName()).log(Level.SEVERE, null, ex);
System.out.println(sid+":ioerror, killing");
Main.ui.commitln(sid+":ioerror, killing");
//client.close();
kill();
}
}
@Override
public void run()
{
try
{
while( ! kill )
{
Apart = null;
Values = null;
//System.out.println(sid+":awaiting headers");
int bit = -2;
int anticipate = 0;
Data = null;
int read = 0;
int tick = 0;
//String apart[] = null;
//String values[] = null;
r = null;
while( true )
{
tick ++;
yield();
try
{
sleep(1);
}
catch (InterruptedException ex)
{
Logger.getLogger(Seat.class.getName()).log(Level.SEVERE, null, ex);
}
if( In.ready() )
{
if( bit == -2 )
{
if( (Switch = In.read()) != Lever )
{
Lever = ( Lever == 1 ) ? 0 : 1;
bit = -1;
continue;
}
else
{
System.out.println(sid+":disorder " + Lever + ":" + Switch);
}
}
if(bit != 0)
{
anticipate += bit = In.read();
if( bit == 127 ) continue; else bit = 0;
cbuf = CharBuffer.allocate(anticipate);
continue;
}
if( ( read += In.read(cbuf) ) != anticipate ) continue;
cbuf.rewind();
Data = cbuf.toString();
//System.out.println(sid + ":data: " + Data);
Parser();
break;
}
}
}
System.out.println(sid+":eo seat");
//kill();
}
catch (IOException ex)
{
System.out.println(sid+":ioerror");
Logger.getLogger(Seat.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void Parser()
{
try
{
String singles[] = Data.split(",");
for( int I = 0; I < singles.length; I ++)
{
Apart = singles[I].split(":");
if( Apart.length > 1 ) Values = Apart[1].split("/");
if ( Apart[0].equals("0") )
{
boolean Sent = false;
do
{
if( Frags.notEmpty() )
{
Send("");
Sent = true;
break;
}
sleep(1);// Todo: Find a prettier way to do this.
} while ( ! In.ready() );
if( ! Sent ) Lever = ( Lever == 1 ) ? 0 : 1;
break;
}
if ( Apart[0].equals( "hello" ) )
{
if( ! Bus.containsKey(pid) )
{
Statement GenericSttmnt = Main.sql.createStatement();
String GenericQuery = "INSERT INTO player VALUES(NULL, '" + client.getRemoteSocketAddress() + "', 'Nameless', 15, 9, 0, 0) ";
int GenericRow = GenericSttmnt.executeUpdate(GenericQuery, Statement.RETURN_GENERATED_KEYS);
//System.out.print(GenericRow);
SelfQuery = "SELECT player.*, entity.*, region.rtype FROM player " +
"LEFT JOIN tile ON player.ptid = tile.tid " +
"LEFT JOIN entity ON tile.tid = entity.eid " +
"LEFT JOIN region ON player.prid = region.rid " +
"WHERE pip = '" + client.getRemoteSocketAddress() + "' ";
//SelfRow.refreshRow();
SelfSttmnt = Main.sql.createStatement();
SelfRow = SelfSttmnt.executeQuery( SelfQuery );
//SelfRow.beforeFirst();
SelfRow.beforeFirst();
SelfRow.next();
pid = SelfRow.getInt("pid");
p = new Player(SelfRow.getInt("pid"), SelfRow.getString("pname"), SelfRow.getInt("px"), SelfRow.getInt("py") );
Bus.put(pid, this);
System.out.println(sid+":pid: "+pid);
Lever = ( Lever == 1 ) ? 0 : 1;
}
else r = "Kill Yourself";
}
else if ( Apart[0].equals("region") )
{
//Statement SelfRowsttmnt = server.sql.createStatement();
//SelfRow = SelfSttmnt.executeQuery("SELECT * FROM player WHERE pip = '" + client.getRemoteSocketAddress() + "' ");
//SelfRow.refreshRow();
Statement TileStatement = Main.sql.createStatement();
ResultSet TileRows;
Statement PlayerStatement = Main.sql.createStatement();
ResultSet PlayerRows;
Statement RegionStatement = Main.sql.createStatement();
ResultSet RegionRows;
SelfRow.beforeFirst();
SelfRow.next();
String TileQuery = "SELECT * FROM tile "
+ "LEFT JOIN entity ON tile.tid = entity.eid "
+ "WHERE "
+ "tx >= " + ( SelfRow.getInt("px")-1 - ((w / 40) / 2) ) + " AND "
+ "tx <= " + ( SelfRow.getInt("px")+1 + ((w / 40) / 2) ) + " AND "
+ "ty >= " + ( SelfRow.getInt("py")-1 - ((h / 40) / 2) ) + " AND "
+ "ty <= " + ( SelfRow.getInt("py")+1 + ((h / 40) / 2) );
String RegionQuery = "SELECT * FROM region WHERE "
+ "rsx >= " + ( SelfRow.getInt("px")-1 - ((w / 40) / 2) ) + " AND "
+ "rsy <= " + ( SelfRow.getInt("px")+1 + ((w / 40) / 2) ) + " AND "
+ "rex >= " + ( SelfRow.getInt("py")-1 - ((h / 40) / 2) ) + " AND "
+ "rey <= " + ( SelfRow.getInt("py")+1 + ((h / 40) / 2) );
String PlayerQuery = "SELECT * FROM player WHERE "
+ " px >= " + ( SelfRow.getInt("px")-1 - ((w / 40) / 2) ) + " AND"
+ " px <= " + ( SelfRow.getInt("px")+1 + ((w / 40) / 2) ) + " AND"
+ " py >= " + ( SelfRow.getInt("py")-1 - ((h / 40) / 2) ) + " AND"
+ " py <= " + ( SelfRow.getInt("py")+1 + ((h / 40) / 2) ) + " AND pid != " + pid;
PlayerRows = PlayerStatement.executeQuery(PlayerQuery);
TileRows = TileStatement.executeQuery(TileQuery);
RegionRows = RegionStatement.executeQuery(RegionQuery);
while( TileRows.next() )
{
r=(r!=null)?r+",":"";
r = r + "t:" +
TileRows.getInt(1) + "/" +
TileRows.getString("timage") + "/" +
TileRows.getString("tdecal") + "/" +
TileRows.getInt("tx") + "/" +
TileRows.getInt("ty") + "/" +
TileRows.getInt("trid");
if( TileRows.getInt("eid") != 0 )
r = r + ",e:" +
TileRows.getInt(1) + "/" +
TileRows.getString("etype") + "/" +
TileRows.getInt("eparama") + "/" +
TileRows.getInt("eparamb") + "/" +
TileRows.getInt("eparamc") + "/";
}
while( RegionRows.next() )
r = r + ",r:" +
RegionRows.getInt(1) + "/" +
RegionRows.getString("rtype") + "/" +
RegionRows.getString("rname") + "/" +
RegionRows.getString("rsx") + "/" +
RegionRows.getString("rsy") + "/" +
RegionRows.getString("rex") + "/" +
RegionRows.getString("rey");
r = r + "," + p.Write();
/*while( PlayerRows.next() )
r = r + ",p:" + PlayerRows.getInt("pid") + "/" + PlayerRows.getString("pname") + "/" + PlayerRows.getInt("px") + "/" + PlayerRows.getInt("py");*/
//System.out.print(r);
//System.out.print("Sent players and tiles. ");
}
else if ( Apart[0].equals("move") )
{
Statement TileSttmnt = Main.sql.createStatement();
ResultSet TileRow;
SelfRow.beforeFirst();
SelfRow.next();
int d = Integer.parseInt( Values[0] );
if ( d <= 3 && d >= 0 )
{
while( true ) // so we may break
{
int[] dS = sutil.Direction( SelfRow.getInt("px"), SelfRow.getInt("py"), d );
SelfRow.beforeFirst();
SelfRow.next();
String TileQuery = "SELECT tile.*, entity.*, region.rtype FROM tile "
+ "LEFT JOIN entity ON tile.tid = entity.eid "
+ "LEFT JOIN region ON tile.trid = region.rid "
+ "WHERE tile.tx = " + dS[0] + " AND tile.ty = " + dS[1] + " ";
//System.out.print(TileQuery);
TileRow = TileSttmnt.executeQuery(TileQuery);
if( TileRow.next() )
{
boolean Same = TileRow.getInt("trid") == SelfRow.getInt("prid");
boolean Inside = SelfRow.getInt("rtype") == 1;
if (! Same )
{
if( TileRow.getInt("rtype") == 1 || SelfRow.getInt("rtype") == 1 )
{
if( ! Inside )
{
if( TileRow.getString("etype") != null && TileRow.getString("etype").equals("door") )
{
if( Opposite[ TileRow.getInt("eparama") ] != d ) break;
} else break;
}
else
{
if( SelfRow.getString("etype") != null && SelfRow.getString("etype").equals("door") )
{
if( SelfRow.getInt("eparama") != d ) break;
} else break;
}
}
}
Statement PlayerStatement = Main.sql.createStatement();
String PlayerQuery = "UPDATE player SET px = " + dS[0] + ", py = " + dS[1] + ", ptid = " + TileRow.getInt("tid") + ", prid = " + TileRow.getInt("trid") + " WHERE pid = " + pid;
PlayerStatement.execute( PlayerQuery );
SelfRow = SelfSttmnt.executeQuery(SelfQuery);
SelfRow.next();
Frags.Patch( p = new Player( SelfRow.getInt("pid"), SelfRow.getString("pname"), dS[0], dS[1] ) );
for( Seat s : Bus.values() )
{
Seat Scapegoat, Sin;
Scapegoat = ( this.sid > s.sid ) ? s : this;
Sin = ( Scapegoat == this ) ? s : this;
if ( s == this ) continue;
if ( Scapegoat.See(Sin) )
{
if ( !Scapegoat.Seen(Sin) )
{
Scapegoat.Seen.add(Sin);
Frags.Patch( s.p );
}
s.Frags.Patch( p );
}
else if ( Scapegoat.Seen(Sin) )
{
Scapegoat.Seen.remove(Sin);
s.Frags.Patch( new Player( pid ) );
}
}
r = "";
}
break;
}
}
}
else
{
System.out.println(sid+":unknown: "+Data);
kill = true;
r = "Kill Yourself";
}
Send(r);
}
}
catch (InterruptedException ex)
{
}
catch (SQLException ex)
{
Logger.getLogger(Seat.class.getName()).log(Level.SEVERE, null, ex);
}
catch (IOException ex)
{
Logger.getLogger(Seat.class.getName()).log(Level.SEVERE, null, ex);
}
}
boolean Seen( Seat s )
{
return Seen.contains(s);
}
boolean See( Seat s ) throws SQLException
{
if(
SelfRow.getInt("prid") == s.SelfRow.getInt("prid")
&& s.SelfRow.getInt("px") >= ( SelfRow.getInt("px")-1 - ((w / 40) / 2) )
&& s.SelfRow.getInt("px") <= ( SelfRow.getInt("px")+1 + ((w / 40) / 2) )
&& s.SelfRow.getInt("py") >= ( SelfRow.getInt("py")-1 - ((h / 40) / 2) )
&& s.SelfRow.getInt("py") <= ( SelfRow.getInt("py")+1 + ((h / 40) / 2) )
) return true;
return false;
}
}