From a9e4e95687a893edf9720c05fc24e46054e861df Mon Sep 17 00:00:00 2001 From: rarkenin Date: Sat, 3 May 2014 20:47:30 -0400 Subject: [PATCH] lots of client rework --- .zanata-cache/etag-cache.xml | 2 + README.md | 2 +- mosstest.iml | 2 +- pom.xml | 6 + src/net/mosstest/client/ClientDispatcher.java | 134 ++++++++++++++++++ .../ClientNetworkingManager.java | 32 +++-- src/net/mosstest/client/Messages.java | 49 +++++++ src/net/mosstest/client/MossClient.java | 71 ++++++++++ .../mosstest/client/RemoteFileManager.java | 6 +- src/net/mosstest/client/messages.properties | 19 +++ .../mosstest/launcher/messages_it.properties | 51 +++++++ .../netcommand/MalformedPacketException.java | 2 +- .../netcommand/ToClientAuthDenied.java | 113 +++++++++++++++ .../netcommand/ToClientAuthRequested.java | 12 +- .../netcommand/ToClientCommand.java | 2 +- .../mosstest/netcommand/ToServerCommand.java | 10 ++ .../mosstest/netcommand/ToServerHello.java | 43 ++++++ src/net/mosstest/scripting/MossScriptEnv.java | 34 +++-- src/net/mosstest/scripting/Player.java | 2 + .../mosstest/scripting/WrappedHandler.java | 23 +++ .../mosstest/scripting/messages_it.properties | 4 + .../ApplicationLevelNetworkingManager.java | 1 + .../mosstest/servercore/ClientManager.java | 2 + .../mosstest/servercore/CommonNetworking.java | 6 +- .../mosstest/servercore/EventProcessor.java | 34 ++--- .../mosstest/servercore/MossNetPacket.java | 33 +---- src/net/mosstest/servercore/MossWorld.java | 2 + .../servercore/messages_it.properties | 53 +++++++ 28 files changed, 676 insertions(+), 74 deletions(-) create mode 100644 .zanata-cache/etag-cache.xml create mode 100644 src/net/mosstest/client/ClientDispatcher.java rename src/net/mosstest/{servercore => client}/ClientNetworkingManager.java (93%) create mode 100644 src/net/mosstest/client/Messages.java create mode 100644 src/net/mosstest/client/messages.properties create mode 100644 src/net/mosstest/launcher/messages_it.properties rename src/net/mosstest/{servercore => }/netcommand/MalformedPacketException.java (67%) create mode 100644 src/net/mosstest/netcommand/ToClientAuthDenied.java rename src/net/mosstest/{servercore => }/netcommand/ToClientAuthRequested.java (92%) rename src/net/mosstest/{servercore => }/netcommand/ToClientCommand.java (63%) create mode 100644 src/net/mosstest/netcommand/ToServerCommand.java create mode 100644 src/net/mosstest/netcommand/ToServerHello.java create mode 100644 src/net/mosstest/scripting/WrappedHandler.java create mode 100644 src/net/mosstest/scripting/messages_it.properties create mode 100644 src/net/mosstest/servercore/messages_it.properties diff --git a/.zanata-cache/etag-cache.xml b/.zanata-cache/etag-cache.xml new file mode 100644 index 0000000..5cd9553 --- /dev/null +++ b/.zanata-cache/etag-cache.xml @@ -0,0 +1,2 @@ + + diff --git a/README.md b/README.md index 63ffe00..89eb03c 100644 --- a/README.md +++ b/README.md @@ -7,4 +7,4 @@ Pull requesters: Don't touch the thread pool or the scripting interface. Electrocution, drowning, or security bots attacking you may occur. -pom.xml refers to non-maven jars in a custom jMonkey reporitory. Please hold as our server will have that repository available for download soon. +pom.xml refers to non-maven jars in a custom jMonkey repository. `pom.xml` refers to that repository, although it may go down when the forum or wiki goes down for updates or maintenance. diff --git a/mosstest.iml b/mosstest.iml index d6d4e78..476f474 100644 --- a/mosstest.iml +++ b/mosstest.iml @@ -10,7 +10,6 @@ - @@ -45,6 +44,7 @@ + diff --git a/pom.xml b/pom.xml index 238bf63..5657a05 100644 --- a/pom.xml +++ b/pom.xml @@ -336,6 +336,12 @@ annotations 9.0.4 + + commons-codec + commons-codec + 1.9 + + diff --git a/src/net/mosstest/client/ClientDispatcher.java b/src/net/mosstest/client/ClientDispatcher.java new file mode 100644 index 0000000..3a1009c --- /dev/null +++ b/src/net/mosstest/client/ClientDispatcher.java @@ -0,0 +1,134 @@ +package net.mosstest.client; + +import net.mosstest.netcommand.MalformedPacketException; +import net.mosstest.netcommand.ToClientAuthDenied; +import net.mosstest.netcommand.ToClientAuthRequested; +import net.mosstest.servercore.MossNetPacket; +import net.mosstest.servercore.MosstestFatalDeathException; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.log4j.Logger; + +import java.io.IOException; +import java.text.MessageFormat; + +/** + * Created by hexafraction on 4/27/14. + */ +public class ClientDispatcher { + public static final byte[] EMPTY_PAYLOAD = {}; + private MossClient client; + private boolean hasAuthed, hasBootstrapped; + + private static final Logger logger = Logger.getLogger(ClientDispatcher.class); + + public void dispatch(MossNetPacket inbound) { + + this.dispatch0(inbound); + + } + + + private void dispatch0(MossNetPacket inbound) { + switch (inbound.commandId) { + case 0x01: //TOCLIENT_AUTH_REQUESTED + handleAuthRequested(inbound); + break; + case 0x03: //TOCLIENT_AUTH_DENIED + handleAuthDenied(inbound); + break; + case 0x00: //SYS_NOP + case 0xFE: //SYS_BIND_CODE + case 0xFF: //SYS_QUENCH + // fall-through for packets already handled at a lower level + break; + default: + logger.warn(Messages.getString("PACKET_NOT_DISPATCHABLE")); + } + } + + private void handleAuthDenied(MossNetPacket inbound) { + try { + ToClientAuthDenied parsed = new ToClientAuthDenied(inbound.payload); + switch (parsed.getReason()) { + case REASON_UNKNWN: + logger.fatal(Messages.getString("AUTH_FAILED_UNKNWN")); + break; + case REASON_BAD_PASS: + logger.fatal(Messages.getString("AUTH_FAILED_BAD_PASS")); + break; + case REASON_BANNED: + logger.fatal(Messages.getString("AUTH_FAILED_BAN")); + break; + case REASON_PLAYER_LIMIT: + logger.fatal(Messages.getString("AUTH_FAILED_PLAYER_LIM")); + break; + case REASON_LOGON_HOUR: + logger.fatal(Messages.getString("AUTH_FAILED_LOGON_HOUR")); + break; + case REASON_NO_NEW_PLAYERS: + logger.fatal(Messages.getString("AUTH_FAILED_NO_REGISTER")); + break; + case REASON_VERSION_MISMATCH: + logger.fatal(Messages.getString("AUTH_FAILED_VERSION")); + break; + case REASON_AUTH_TIMED_OUT: + logger.fatal(Messages.getString("AUTH_FAILED_TIMEOUT")); + break; + case REASON_SERVER_MAINT: + logger.fatal(Messages.getString("AUTH_FAILED_MAINTENANCE")); + break; + case REASON_FAILED_CONNECTION: + logger.fatal(Messages.getString("AUTH_FAILED_CONN")); + break; + } + } catch (IOException e) { + logger.fatal(Messages.getString("IOEXCEPTION_DESERIALIZE_AUTH_FAIL_PCKT")); + throw new MosstestFatalDeathException(e); + } + } + + private void handleAuthRequested(MossNetPacket inbound) { + if (hasAuthed) { + logger.error(Messages.getString("ALREADY_AUTHED")); + return; + } + try { + ToClientAuthRequested parsed = new ToClientAuthRequested(inbound.payload); + authenticate(parsed); + } catch (IOException e) { + logger.fatal(Messages.getString("IOEXCEPTION_DESERIALIZE_AUTH_PCKT")); + throw new MosstestFatalDeathException(e); + } catch (MalformedPacketException e) { + logger.warn(Messages.getString("MALFORMED_TC_AUTH_REQUESTED")); + } + } + + private void authenticate(ToClientAuthRequested parsed) throws IOException { + + byte[] pass = client.getPassword(); + switch (parsed.getAuthType()) { + case AUTH_NIL: + logger.warn(Messages.getString("SVR_NO_AUTH")); + client.net.sendPacket(new MossNetPacket(0x02, EMPTY_PAYLOAD)); + case AUTH_PLAIN: + logger.warn(Messages.getString("SVR_AUTH_PLAIN")); + // FIXME some sort of confirmation dialog + client.net.sendPacket(new MossNetPacket(0x02, pass)); + case AUTH_HASH_SHA512: + client.net.sendPacket(new MossNetPacket(0x02, DigestUtils.sha512( + ArrayUtils.addAll( + ArrayUtils.addAll( + client.getUsername().getBytes(), pass), parsed.getAuthParam() + ) + ) + ) + ); + case AUTH_CHALLENGE_RESPONSE: + logger.fatal(Messages.getString("SERVER_AUTH_CHALLENGE_RESP")); + throw new MosstestFatalDeathException(Messages.getString("AUTH_CHAP_FAILED")); + } + + + } +} diff --git a/src/net/mosstest/servercore/ClientNetworkingManager.java b/src/net/mosstest/client/ClientNetworkingManager.java similarity index 93% rename from src/net/mosstest/servercore/ClientNetworkingManager.java rename to src/net/mosstest/client/ClientNetworkingManager.java index ea9c446..60f0547 100644 --- a/src/net/mosstest/servercore/ClientNetworkingManager.java +++ b/src/net/mosstest/client/ClientNetworkingManager.java @@ -1,5 +1,9 @@ -package net.mosstest.servercore; +package net.mosstest.client; +import net.mosstest.servercore.ClientManager; +import net.mosstest.servercore.CommonNetworking; +import net.mosstest.servercore.Messages; +import net.mosstest.servercore.MossNetPacket; import org.apache.log4j.Logger; import java.io.*; @@ -24,6 +28,8 @@ public class ClientNetworkingManager { public static final int PACKET_QUEUE_CAPACITY = 1024; public static final int TIME_TO_KEEPALIVE = 4000; public static final byte[] EMPTY_PAYLOAD = new byte[]{}; + + public static final MossNetPacket QUENCH_PACKET = new MossNetPacket(CMD_QUENCH, EMPTY_PAYLOAD, true, true, true); /** * The logger. */ @@ -125,7 +131,7 @@ public class ClientNetworkingManager { * performance */ /** - * The packets. + * The packet receive queue */ public ArrayBlockingQueue packets = new ArrayBlockingQueue<>( PACKET_QUEUE_CAPACITY); @@ -351,7 +357,7 @@ public class ClientNetworkingManager { this.bulkReadHandler.start(); this.fastReadHandler.start(); this.dgramReadHandler.start(); - /* The send queue thread. */ + /* The send queue thread. */ Thread sendQueueThread = new Thread(new Runnable() { @Override @@ -433,7 +439,13 @@ public class ClientNetworkingManager { ClientNetworkingManager.this.lastUdpOut .get(), ClientNetworkingManager.this.quenchedSince - .get()))))))); + .get() + ) + ) + ) + ) + ) + )); } catch (InterruptedException e) { // pass } @@ -451,25 +463,23 @@ public class ClientNetworkingManager { * @param seqnum the seqnum */ protected void sendAck(int seqnum) { - // TODO Auto-generated method stub - + logger.error("UDP acks are not supported at this time."); } /** * Send tos udp conn. */ protected void sendTosUdpConn() { - // TODO Auto-generated method stub - + logger.error("UDP connections are not supported at this time."); } /** - * Send quench. + * Send QUENCH_PACKET. */ - protected void sendQuench() { + protected void sendQuench() throws IOException { // TODO Sends a request for the server to back off with data and skip // non-essential data. - + this.sendPacket(QUENCH_PACKET); } /** diff --git a/src/net/mosstest/client/Messages.java b/src/net/mosstest/client/Messages.java new file mode 100644 index 0000000..7685fa1 --- /dev/null +++ b/src/net/mosstest/client/Messages.java @@ -0,0 +1,49 @@ +package net.mosstest.client; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +// TODO: Auto-generated Javadoc + +/** + * The Class Messages. + */ +public class Messages { + + /** The Constant BUNDLE_NAME. */ + private static final String BUNDLE_NAME = "net.mosstest.client.messages"; //$NON-NLS-1$ + + /** The res bundle. */ + private static ResourceBundle resBundle = ResourceBundle + .getBundle(BUNDLE_NAME); + + /** + * Change language. + * + * @param identifier the identifier + */ + public static void changeLanguage(Locale identifier) { + resBundle = ResourceBundle.getBundle(BUNDLE_NAME, identifier); + } + + /** + * Instantiates a new messages. + */ + private Messages() { + } + + /** + * Gets the string. + * + * @param key the key + * @return the string + */ + public static String getString(String key) { + try { + return resBundle.getString(key); + } catch (MissingResourceException e) { + return '!' + key + '!'; + } + } +} diff --git a/src/net/mosstest/client/MossClient.java b/src/net/mosstest/client/MossClient.java index 171fd37..30b3a29 100644 --- a/src/net/mosstest/client/MossClient.java +++ b/src/net/mosstest/client/MossClient.java @@ -1,9 +1,80 @@ package net.mosstest.client; +import net.mosstest.netcommand.ToServerHello; +import net.mosstest.scripting.MossScriptEnv; +import net.mosstest.scripting.NodePosition; +import net.mosstest.scripting.Player; +import net.mosstest.servercore.MossNetPacket; +import net.mosstest.servercore.MosstestSecurityManager; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; + /** * Created by hexafraction on 4/26/14. */ public class MossClient { + public static final short PROTOCOL_VERSION = 1; + private String username; RemoteFileManager fileManager; + ClientNetworkingManager net; + private byte[] password; + public ClientState getState() { + return state; + } + + private volatile ClientState state; + + private Player ownPlayer; + + private ClientDispatcher dispatcher; + + public MossClient(String remoteHost, int port, String username, byte[] pass) throws IOException, InterruptedException { + this.username = username; + this.password = pass; + this.state = ClientState.PREPARING; + this.fileManager = RemoteFileManager.getInstance(); + this.state = ClientState.CONNECTING; + this.fileManager.setClient(this); + this.net = new ClientNetworkingManager(remoteHost, port, false); // so far no UDP + // we need to send the hello to kick things off + this.net.sendPacket(new MossNetPacket(0x01, new ToServerHello(username, PROTOCOL_VERSION, MossScriptEnv.MIN_SCRIPT_API_VERSION, MossScriptEnv.MAX_SCRIPT_API_VERSION).toByteArray())); + } + + + public byte[] getPassword() { + + SecurityManager sm = System.getSecurityManager(); + if (sm instanceof MosstestSecurityManager) { + ((MosstestSecurityManager) sm).checkMosstestControl(); + } + + return password; + } + + public void setPassword(byte[] password) { + this.password = password; + } + + public String getUsername() { + return username; + } + + public enum ClientState { + PREPARING, + CONNECTING, + BUILDING_FILE_LIST, + FETCHING_FILES, + EXECUTING_STARTUP_SCRIPTS, + RENDERER_STARTING, + PLAYING, + CRASHED, + TIMED_OUT + } } diff --git a/src/net/mosstest/client/RemoteFileManager.java b/src/net/mosstest/client/RemoteFileManager.java index 8edf3b5..dca92ae 100644 --- a/src/net/mosstest/client/RemoteFileManager.java +++ b/src/net/mosstest/client/RemoteFileManager.java @@ -38,10 +38,14 @@ public class RemoteFileManager implements IFileManager { private HashMap knownByName = new HashMap<>(); private HashMap knownByHash = new HashMap<>(); - private File cacheBasedir; + private File cacheBasedir = new File("cache"); // used to request files private MossClient client; + public void setClient(MossClient client) { + this.client = client; + } + @Override public RemoteFile getFile(String name) throws IOException { return knownByName.get(name); diff --git a/src/net/mosstest/client/messages.properties b/src/net/mosstest/client/messages.properties new file mode 100644 index 0000000..7b539b9 --- /dev/null +++ b/src/net/mosstest/client/messages.properties @@ -0,0 +1,19 @@ +IOEXCEPTION_DESERIALIZE_AUTH_PCKT=IOException deserializing an authentication packet, or sending its reply. +IOEXCEPTION_DESERIALIZE_AUTH_FAIL_PCKT=IOException deserializing an authentication failure packet, or sending its reply. +AUTH_FAILED_UNKNWN=Authentication failed for an unknown reason +AUTH_FAILED_BAD_PASS=Authentication failed due to a bad password. +AUTH_FAILED_BAN=You are banned. +AUTH_FAILED_PLAYER_LIM=The server is at its player limit; no more players can join. +AUTH_FAILED_LOGON_HOUR=A server reports a logon hour restriction. The meaning of this may depend as Mosstest does not use this type of failure in its default implementation +AUTH_FAILED_NO_REGISTER=The server is not allowing new players to register. +AUTH_FAILED_VERSION=The server and client versions do not match and no common version can be negotiated upon. +AUTH_FAILED_TIMEOUT=Authentication has timed out +AUTH_FAILED_MAINTENANCE=The server is undergoing maintenance. Generally, only administrators can join in such a case +AUTH_FAILED_CONN=The connection failed; cannot authenticate +ALREADY_AUTHED=Server request authentication, but we've already authenticated. Throwing away request for security. +SVR_NO_AUTH=Server is not using authentication... +SVR_AUTH_PLAIN=Server is requesting password in plain text. +SERVER_AUTH_CHALLENGE_RESP=Challenge-response authentication is not supported at this time. +AUTH_CHAP_FAILED=Challenge-Response auth unsupported +MALFORMED_TC_AUTH_REQUESTED=Malformed TOCLIENT_AUTH_REQUESTED packet. +PACKET_NOT_DISPATCHABLE=Received a packet that cannot be dispatched at this time. \ No newline at end of file diff --git a/src/net/mosstest/launcher/messages_it.properties b/src/net/mosstest/launcher/messages_it.properties new file mode 100644 index 0000000..baaeb03 --- /dev/null +++ b/src/net/mosstest/launcher/messages_it.properties @@ -0,0 +1,51 @@ +GUIBugReportDialog.DLG_BUG_DESC=Descrizione dettagliata del problema\: +GUIBugReportDialog.DLG_BUG_DESC_DEFAULT=Per favore descrivete qui il vostro problema, preferibilmente includendo quello che vi aspettavate che succedesse, che cosa \u00E8 successo, e qualsiasi altro dettaglio riguardante il mondo o il gioco.\n\nPer favore tenete presente che non possiamo aiutarvi con giochi o mod di terze parti. +GUIBugReportDialog.DLG_BUG_EMAIL=e-mail (facoltativa)\: +GUIBugReportDialog.DLG_BUG_NAME=Nome\: +GUIBugReportDialog.DLG_BUG_SUMMARY=Riassunto del problema\: +GUIBugReportDialog.DLG_BUG_TITLE=Segnalare un bug +GUIBugReportDialog.DLG_CHECKBOX_INCLUDE_TECH_INFO=Includere informazioni tecniche +GUIBugReportDialog.DLG_CXL=Annullare +GUIBugReportDialog.DLG_OK=OK +GUIBugReportDialog.DLG_SUBMIT=Inviare +GUIBugReportDialog.NOTICE_INFO_INCLUDED=Se questa casella viene marcata verranno aggiunte alla segnalazione del bug le seguenti informazioni\: \n\n +GUIClientsideLauncher.23=Segnalare un bug... +GUIClientsideLauncher.24=Richiedere una caratteristica nuova... +GUIClientsideLauncher.25=Visitare il sito web +GUIClientsideLauncher.26=Progetto GitHub +GUIClientsideLauncher.27=Visitare i forum +GUIClientsideLauncher.COL_GAME_PRESET=Gioco preimpostato +GUIClientsideLauncher.COL_WORLD_DESC=Descrizione +GUIClientsideLauncher.COL_WORLD_NAME=Nome del mondo +GUIClientsideLauncher.DLG_ABOUT=Informazioni +GUIClientsideLauncher.DLG_DELETE=Cancellare... +GUIClientsideLauncher.DLG_NEW=Nuovo... +GUIClientsideLauncher.DLG_NO_WORLD_TO_DELETE=Non \u00E8 stato scelto nessun mondo da cancellare. Per favore selezionate un mondo esistente nella tabella. +GUIClientsideLauncher.DLG_PLAY=Giocare +GUIClientsideLauncher.DLG_SETTINGS=Impostazioni... +GUIClientsideLauncher.DLG_SINGLEPLAYER=Giocatore singolo +GUIClientsideLauncher.DLG_TITLE=Avviatore del Client Mosstest <0.0.1-initial> +GUIClientsideLauncher.ERR_NO_WORLD_SELECTED=Non \u00E8 stato selezionato nessun mondo da avviare. Per favore selezionate un mondo esistente nella tabella, o create un mondo nuovo. +GUIClientsideLauncher.ERR_NO_WORLD_SELECTED_TITLE=Nessun mondo selezionato +GUIClientsideLauncher.NOTICE_DEFAULT_GAME_CODE=Il codice e le immagini predefinite del gioco sono state create da dolinksy296, hexafraction, e altri.\n +GUIClientsideLauncher.NOTICE_PRIMARY_AUTHORS=Creato da hexafraction, thatnerd2, e altri.\n +GUIClientsideLauncher.NOTICE_TOOLS_USED=Creato con l'aiuto di Eclipse, Git, Maven e innumerevoli servizi come TravisCI e GitHub.\n +GUIClientsideLauncher.SYS_NEWLINE=\n +GUIClientsideLauncher.USES_LIBS=Utilizza le librerie seguenti\:\n +GUIClientsideLauncher.WARN_SET_LAF=Avviso\: l'aspetto non pu\u00F2 essere applicato al sistema. Si utilizza l'aspetto predefinito. +GUIWorldCreationDialog.CXL=Annullare +GUIWorldCreationDialog.DLG_TITLE=Creare un nuovo mondo per giocatore singolo... +GUIWorldCreationDialog.GAME_PROFILE=Profilo di gioco\: +GUIWorldCreationDialog.OK=OK +GUIWorldCreationDialog.WORLD_DESC=Descrizione\: +GUIWorldCreationDialog.WORLD_NAME=Nome del mondo\: +GUIWorldDeletionDialog.AREYOUSURE_TEXT=Siete certi di volere cancellare {0}? Ci\u00F2 non pu\u00F2 essere annullato. +GUIWorldDeletionDialog.DLG_TITLE=Cancellare un mondo per giocatore singolo... +GUIWorldDeletionDialog.NO=No +GUIWorldDeletionDialog.QUESTIONMARK_CANNOT_UNDO=? Questa operazione non pu\u00F2 essere annullata. +GUIWorldDeletionDialog.YES=S\u00EC +GAMEPLAY_NO_WORLD=Si \u00E8 tentato di avviare il gioco senza selezionare un mondo. +GAME_UNCAUGHT_EXCEPT=Eccezione non notata nel codice del gioco, apertura del segnalatore di bug. +STACKTRACE_WRITTEN=Lo stack trace \u00E8 stato scritto su {0} +WORLD_CREATION_CXLD=Creazione del mondo annullata +NO_WORLD_TO_DELETE=Si \u00E8 tentato di cancellare un mondo, ma non ne \u00E8 stato selezionato nessuno. diff --git a/src/net/mosstest/servercore/netcommand/MalformedPacketException.java b/src/net/mosstest/netcommand/MalformedPacketException.java similarity index 67% rename from src/net/mosstest/servercore/netcommand/MalformedPacketException.java rename to src/net/mosstest/netcommand/MalformedPacketException.java index 2ce4194..5d5583f 100644 --- a/src/net/mosstest/servercore/netcommand/MalformedPacketException.java +++ b/src/net/mosstest/netcommand/MalformedPacketException.java @@ -1,4 +1,4 @@ -package net.mosstest.servercore.netcommand; +package net.mosstest.netcommand; /** * The Class MalformedPacketException. diff --git a/src/net/mosstest/netcommand/ToClientAuthDenied.java b/src/net/mosstest/netcommand/ToClientAuthDenied.java new file mode 100644 index 0000000..2d629d0 --- /dev/null +++ b/src/net/mosstest/netcommand/ToClientAuthDenied.java @@ -0,0 +1,113 @@ +package net.mosstest.netcommand; + +import java.io.*; + +/** + * Created by hexafraction on 5/3/14. + */ +public class ToClientAuthDenied extends ToClientCommand { + public enum DenyReason { + REASON_UNKNWN, + REASON_BAD_PASS, + REASON_BANNED, + REASON_PLAYER_LIMIT, + REASON_LOGON_HOUR, + REASON_NO_NEW_PLAYERS, + REASON_VERSION_MISMATCH, + REASON_AUTH_TIMED_OUT, + REASON_SERVER_MAINT, + REASON_FAILED_CONNECTION + } + + public DenyReason getReason() { + return reason; + } + + private final DenyReason reason; + + public ToClientAuthDenied(DenyReason reason) { + this.reason = reason; + } + + public ToClientAuthDenied(byte[] buf) throws IOException { + ByteArrayInputStream bs = new ByteArrayInputStream(buf); + DataInputStream ds = new DataInputStream(bs); + int reason_ = ds.readUnsignedByte(); + switch(reason_){ + case 0x01: + this.reason = DenyReason.REASON_BAD_PASS; + break; + case 0x02: + this.reason = DenyReason.REASON_BANNED; + break; + case 0x03: + this.reason = DenyReason.REASON_PLAYER_LIMIT; + break; + case 0x04: + this.reason = DenyReason.REASON_LOGON_HOUR; + break; + case 0x05: + this.reason = DenyReason.REASON_NO_NEW_PLAYERS; + break; + case 0x06: + this.reason = DenyReason.REASON_PLAYER_LIMIT; + break; + case 0x07: + this.reason = DenyReason.REASON_VERSION_MISMATCH; + break; + case 0x08: + this.reason = DenyReason.REASON_AUTH_TIMED_OUT; + break; + case 0x09: + this.reason = DenyReason.REASON_SERVER_MAINT; + break; + case 0x0a: + this.reason = DenyReason.REASON_FAILED_CONNECTION; + break; + // fall through for unknwn + case 0x00: + default: + this.reason = DenyReason.REASON_UNKNWN; + + } + } + + public byte[] toByteArray() throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(bos); + switch (this.reason) { + + case REASON_UNKNWN: + dos.writeByte(0x00); + break; + case REASON_BAD_PASS: + dos.writeByte(0x01); + break; + case REASON_BANNED: + dos.writeByte(0x02); + break; + case REASON_PLAYER_LIMIT: + dos.writeByte(0x03); + break; + case REASON_LOGON_HOUR: + dos.writeByte(0x04); + break; + case REASON_NO_NEW_PLAYERS: + dos.writeByte(0x06); + break; + case REASON_VERSION_MISMATCH: + dos.writeByte(0x07); + break; + case REASON_AUTH_TIMED_OUT: + dos.writeByte(0x08); + break; + case REASON_SERVER_MAINT: + dos.writeByte(0x09); + break; + case REASON_FAILED_CONNECTION: + dos.writeByte(0x0a); + break; + } + return bos.toByteArray(); + } +} diff --git a/src/net/mosstest/servercore/netcommand/ToClientAuthRequested.java b/src/net/mosstest/netcommand/ToClientAuthRequested.java similarity index 92% rename from src/net/mosstest/servercore/netcommand/ToClientAuthRequested.java rename to src/net/mosstest/netcommand/ToClientAuthRequested.java index b6d800d..a0d77a3 100644 --- a/src/net/mosstest/servercore/netcommand/ToClientAuthRequested.java +++ b/src/net/mosstest/netcommand/ToClientAuthRequested.java @@ -1,5 +1,5 @@ //just keep the same package and import lines -package net.mosstest.servercore.netcommand; +package net.mosstest.netcommand; import java.io.*; @@ -26,7 +26,7 @@ public class ToClientAuthRequested extends ToClientCommand { /** * The Enum AuthType. */ - enum AuthType { + public enum AuthType { /** * The auth nil. @@ -144,4 +144,12 @@ public class ToClientAuthRequested extends ToClientCommand { //Use this line at the end to finish up return bos.toByteArray(); } + + public AuthType getAuthType() { + return authType; + } + + public byte[] getAuthParam() { + return authParam; + } } diff --git a/src/net/mosstest/servercore/netcommand/ToClientCommand.java b/src/net/mosstest/netcommand/ToClientCommand.java similarity index 63% rename from src/net/mosstest/servercore/netcommand/ToClientCommand.java rename to src/net/mosstest/netcommand/ToClientCommand.java index f3ec40d..31e2c2e 100644 --- a/src/net/mosstest/servercore/netcommand/ToClientCommand.java +++ b/src/net/mosstest/netcommand/ToClientCommand.java @@ -1,4 +1,4 @@ -package net.mosstest.servercore.netcommand; +package net.mosstest.netcommand; /** * The Class ToClientCommand. diff --git a/src/net/mosstest/netcommand/ToServerCommand.java b/src/net/mosstest/netcommand/ToServerCommand.java new file mode 100644 index 0000000..bf6a3c9 --- /dev/null +++ b/src/net/mosstest/netcommand/ToServerCommand.java @@ -0,0 +1,10 @@ +package net.mosstest.netcommand; + +/** + * The Class ToServerCommand. + */ +public abstract class ToServerCommand { + + //ignore + +} diff --git a/src/net/mosstest/netcommand/ToServerHello.java b/src/net/mosstest/netcommand/ToServerHello.java new file mode 100644 index 0000000..7647cba --- /dev/null +++ b/src/net/mosstest/netcommand/ToServerHello.java @@ -0,0 +1,43 @@ +package net.mosstest.netcommand; + +import java.io.*; + +/** + * Created by hexafraction on 4/27/14. + */ +public class ToServerHello { + private final String username; + private final int protocolVersion; + private final int minScriptApi; + private final int maxScriptApi; + + public ToServerHello(byte[] buf) throws IOException, + MalformedPacketException { + + // constructor from byte[] is parsing + // Keep lines below for all of these tasks + ByteArrayInputStream bs = new ByteArrayInputStream(buf); + DataInputStream ds = new DataInputStream(bs); + this.protocolVersion = ds.readUnsignedShort(); + this.minScriptApi = ds.readUnsignedShort(); + this.maxScriptApi = ds.readUnsignedShort(); + this.username = ds.readUTF(); + } + + public ToServerHello(String username, int protocolVersion, int minScriptApi, int maxScriptApi) { + this.username = username; + this.protocolVersion = protocolVersion; + this.minScriptApi = minScriptApi; + this.maxScriptApi = maxScriptApi; + } + + public byte[] toByteArray() throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(bos); + dos.writeShort(this.protocolVersion); + dos.writeShort(this.minScriptApi); + dos.writeShort(this.maxScriptApi); + dos.writeUTF(this.username); + return bos.toByteArray(); + } +} \ No newline at end of file diff --git a/src/net/mosstest/scripting/MossScriptEnv.java b/src/net/mosstest/scripting/MossScriptEnv.java index 0b38308..2ebfe85 100644 --- a/src/net/mosstest/scripting/MossScriptEnv.java +++ b/src/net/mosstest/scripting/MossScriptEnv.java @@ -37,11 +37,27 @@ import java.util.List; * @since 0.0 */ public class MossScriptEnv { - + public static final short SCRIPT_API_VERSION = 1; + public static final short MIN_SCRIPT_API_VERSION = 1; + public static final short MAX_SCRIPT_API_VERSION = 1; public void registerNodeChangeHandler(MossNodeChangeHandler h) { } + private InheritableThreadLocal requestedScriptApiVer = new InheritableThreadLocal(){ + @Override + protected Short initialValue() { + return MAX_SCRIPT_API_VERSION; + } + }; + + public void setRequestedScriptApiVer(short requestedScriptApiVer) { + if(requestedScriptApiVer >= MIN_SCRIPT_API_VERSION && requestedScriptApiVer <= MAX_SCRIPT_API_VERSION) + this.requestedScriptApiVer.set(requestedScriptApiVer); + else { + throw new MosstestFatalDeathException("A plugin requests an unsatisfiable script API version."); + } + } private HashMap, ArrayList> eventHandlers; @@ -315,13 +331,13 @@ public class MossScriptEnv { return this.fp; } - private HashMap, List> handlers = new HashMap<>(); + private HashMap, List> handlers = new HashMap<>(); - public List getEventHandlers( + public List getEventHandlers( Class clazz) { - List l = Collections.unmodifiableList(handlers.get(clazz)); + List l = Collections.unmodifiableList(handlers.get(clazz)); if (l == null) { - handlers.put(clazz, new ArrayList()); + handlers.put(clazz, new ArrayList()); return Collections.EMPTY_LIST; } return l; @@ -329,14 +345,12 @@ public class MossScriptEnv { } public void registerHandler(MossEventHandler handler, Class clazz) { - List l = handlers.get(clazz); + List l = handlers.get(clazz); if (l == null) { - l = new ArrayList(); + l = new ArrayList(); handlers.put(clazz, l); - l.add(handler); - return; } - l.add(handler); + l.add(new WrappedHandler(handler, this.requestedScriptApiVer.get())); } diff --git a/src/net/mosstest/scripting/Player.java b/src/net/mosstest/scripting/Player.java index 79595ea..3cda4fd 100644 --- a/src/net/mosstest/scripting/Player.java +++ b/src/net/mosstest/scripting/Player.java @@ -26,6 +26,8 @@ public class Player { */ private HashMap inventories = new HashMap<>(); + public int playerId; + /** * The name. */ diff --git a/src/net/mosstest/scripting/WrappedHandler.java b/src/net/mosstest/scripting/WrappedHandler.java new file mode 100644 index 0000000..680cb35 --- /dev/null +++ b/src/net/mosstest/scripting/WrappedHandler.java @@ -0,0 +1,23 @@ +package net.mosstest.scripting; + +import net.mosstest.scripting.handlers.MossEventHandler; + +/** + * Created by hexafraction on 5/3/14. + */ +public class WrappedHandler { + private final MossEventHandler handler; + private final short requestedApiVer; + public WrappedHandler(MossEventHandler handler, short requestedApiVer) { + this.handler = handler; + this.requestedApiVer = requestedApiVer; + } + + public MossEventHandler getHandler() { + return handler; + } + + public short getRequestedApiVer() { + return requestedApiVer; + } +} diff --git a/src/net/mosstest/scripting/messages_it.properties b/src/net/mosstest/scripting/messages_it.properties new file mode 100644 index 0000000..c0b1f52 --- /dev/null +++ b/src/net/mosstest/scripting/messages_it.properties @@ -0,0 +1,4 @@ +AntiCheatController.THREAD_NAME=antitruffa +MossEvent.MSG_CROSS_DMZ_SECURITY_WARNING=Tentativo di accedere alle risorse controllate nello script DMZ. +ScriptableDatabase.DB_NAME_INVALID=Nome della banca dati non valido. +INV_IOEXCEPTION_FATAL=IOException durante la serializzazione di un inventario. IL MONDO CADRA' A BREVE. diff --git a/src/net/mosstest/servercore/ApplicationLevelNetworkingManager.java b/src/net/mosstest/servercore/ApplicationLevelNetworkingManager.java index a7a2a64..4df0b48 100644 --- a/src/net/mosstest/servercore/ApplicationLevelNetworkingManager.java +++ b/src/net/mosstest/servercore/ApplicationLevelNetworkingManager.java @@ -1,5 +1,6 @@ package net.mosstest.servercore; +import net.mosstest.client.ClientNetworkingManager; import net.mosstest.scripting.Position; // TODO: Auto-generated Javadoc diff --git a/src/net/mosstest/servercore/ClientManager.java b/src/net/mosstest/servercore/ClientManager.java index 9159162..8b24ddb 100644 --- a/src/net/mosstest/servercore/ClientManager.java +++ b/src/net/mosstest/servercore/ClientManager.java @@ -1,5 +1,7 @@ package net.mosstest.servercore; +import net.mosstest.client.ClientNetworkingManager; + import java.io.IOException; diff --git a/src/net/mosstest/servercore/CommonNetworking.java b/src/net/mosstest/servercore/CommonNetworking.java index 00604fc..7277e86 100644 --- a/src/net/mosstest/servercore/CommonNetworking.java +++ b/src/net/mosstest/servercore/CommonNetworking.java @@ -7,11 +7,11 @@ package net.mosstest.servercore; public class CommonNetworking { /** The Constant magic. */ - static final int magic=0xfa7d2e4a; + public static final int magic=0xfa7d2e4a; /** The Constant magicNoAck. */ - static final int magicNoAck=0xfa7d2e4f; + public static final int magicNoAck=0xfa7d2e4f; /** The Constant magicAck. */ - static final int magicAck=0xfa7d2740; + public static final int magicAck=0xfa7d2740; } diff --git a/src/net/mosstest/servercore/EventProcessor.java b/src/net/mosstest/servercore/EventProcessor.java index 28da6ee..846e777 100644 --- a/src/net/mosstest/servercore/EventProcessor.java +++ b/src/net/mosstest/servercore/EventProcessor.java @@ -1,9 +1,6 @@ package net.mosstest.servercore; -import net.mosstest.scripting.MapNode; -import net.mosstest.scripting.MossScriptEnv; -import net.mosstest.scripting.MossScriptException; -import net.mosstest.scripting.NodePosition; +import net.mosstest.scripting.*; import net.mosstest.scripting.events.IMossEvent; import net.mosstest.scripting.events.MossNodeChangeEvent; import net.mosstest.scripting.events.ThreadStopEvent; @@ -27,9 +24,9 @@ import java.util.concurrent.atomic.AtomicInteger; * The Class EventProcessor. * * @author rarkenin, hexafraction - *

+ *

* Blargh. - *

+ *

* This is a nasty thread pool. If you don't understand threading or * Java well, you may want to stick to only accessing the queue as * otherwise asphyxiation, drowning, or chlorine poisoning may occur. @@ -101,10 +98,10 @@ public class EventProcessor { } private void dispatchEvent(IMossEvent evt) { - List evtHandlerList = this.ev + List evtHandlerList = this.ev .getEventHandlers(evt.getClass()); try { - for (MossEventHandler ourHandler : evtHandlerList) { + for (WrappedHandler ourHandler : evtHandlerList) { if (dispatchEventInner(ourHandler, evt)) { return; } @@ -116,13 +113,16 @@ public class EventProcessor { } } - private boolean dispatchEventInner(MossEventHandler ourHandler, + private boolean dispatchEventInner(WrappedHandler wrappedHandler, IMossEvent evt) throws IllegalArgumentException { + MossEventHandler ourHandler = wrappedHandler.getHandler(); try { if (evt instanceof MossNodeChangeEvent) { - - return ((MossNodeChangeHandler) ourHandler) - .onAction((MossNodeChangeEvent) evt); + { + this.ev.setRequestedScriptApiVer(wrappedHandler.getRequestedApiVer()); + return ((MossNodeChangeHandler) ourHandler) + .onAction((MossNodeChangeEvent) evt); + } } else throw new IllegalArgumentException( @@ -174,7 +174,8 @@ public class EventProcessor { processEvents(); } - }); + } + ); threads[c].start(); EventProcessor.this.currentThreads.incrementAndGet(); @@ -199,7 +200,8 @@ public class EventProcessor { processEvents(); } - }).run(); + } + ).run(); EventProcessor.this.currentThreads .incrementAndGet(); @@ -221,11 +223,11 @@ public class EventProcessor { } } } - }, Messages.getString("EventProcessor.THREAD_NAME_MGR")); + }, Messages.getString("EventProcessor.THREAD_NAME_MGR") + ); manager.start(); } - } diff --git a/src/net/mosstest/servercore/MossNetPacket.java b/src/net/mosstest/servercore/MossNetPacket.java index 750b61e..c901698 100644 --- a/src/net/mosstest/servercore/MossNetPacket.java +++ b/src/net/mosstest/servercore/MossNetPacket.java @@ -4,40 +4,19 @@ package net.mosstest.servercore; import java.util.Arrays; -/** - * The Class MossNetPacket. - */ public class MossNetPacket { - /** - * The command id. - */ - int commandId; + public int commandId; - /** - * The payload. - */ - byte[] payload; + public byte[] payload; - /** - * The needs fast. - */ - boolean needsFast; + public boolean needsFast; - /** - * The needs ack. - */ - boolean needsAck; + public boolean needsAck; - /** - * The is important. - */ - boolean isImportant; + public boolean isImportant; - /** - * The sess. - */ - ServerSession sess; + public ServerSession sess; /** * Constructs a packet, for either sending or from receiving. diff --git a/src/net/mosstest/servercore/MossWorld.java b/src/net/mosstest/servercore/MossWorld.java index 94d066c..ea5c01f 100644 --- a/src/net/mosstest/servercore/MossWorld.java +++ b/src/net/mosstest/servercore/MossWorld.java @@ -14,6 +14,7 @@ import org.jetbrains.annotations.NonNls; import java.io.File; import java.io.IOException; import java.util.List; +import java.util.Locale; public class MossWorld { static { @@ -72,6 +73,7 @@ public class MossWorld { @SuppressWarnings("nls") public MossWorld(@NonNls String name, int port) throws MossWorldLoadException, MapDatabaseException, IOException { + //Thread.currentThread().setContextClassLoader( // MosstestSecurityManager.instance.getScriptClassLoader(Thread // .currentThread().getContextClassLoader())); diff --git a/src/net/mosstest/servercore/messages_it.properties b/src/net/mosstest/servercore/messages_it.properties new file mode 100644 index 0000000..45b7990 --- /dev/null +++ b/src/net/mosstest/servercore/messages_it.properties @@ -0,0 +1,53 @@ +AbstractNodeManager.DESC_UNKNOWN_NODE=Un pezzo sconosciuto del mondo +ClientNetworkingManager.DESC_NETWORK_TIMEOUT=La connessione al server \u00E8 stata persa o \u00E8 diventata troppo lenta per continuare. \nProbabilmente questo \u00E8 dovuto a una connessione instabile, WiFi debole, cavi allentati, o un problema di firewall. +ClientNetworkingManager.THREAD_NET_TIMEOUT=netTimeout +ClientNetworkingManager.THREAD_QUEUEING=netClientSendQueue +DefaultEventHandlers.NO_SUCH_CMD=Comando di chat inesistente. +EventProcessor.MSG_ADD_DYNAMIC=Thread aggiunto dinamicamente +EventProcessor.MSG_STOP_ONE_THREAD=Arresto di un thread... +EventProcessor.MSG_THREAD_START=E' iniziato un thread di lavoro. +EventProcessor.THREAD_NAME_MGR=EventProcessorManager +EventProcessor.THREADGROUP=EventProcessor +FuturesProcessor.FUTURES_THREAD=futuri +LocalRenderPreparator.MG_EXCEPT=Il generatore di mappe ha emesso una eccezione. +LocalRenderPreparator.MSG_REQUESTED=Aree richieste {0}, {1}, {2}. +LocalRenderPreparator.START_MSG=Il preparatore di rendering locale si sta avviando. +MapChunk.BAD_SER_VER=Versione di serializzazione sbagliata +MapDatabase.ERR_DB_FAIL=Caricamento della banca dati fallito. +MossDebugUtils.27=git.build.time +MossDebugUtils.MSG_BUILT_ON=Costruito su\: +MossDebugUtils.MSG_CORES=Processori disponibili\: +MossDebugUtils.MSG_EXCEPTION_CAUGHT=<<>> \n +MossDebugUtils.MSG_FREE_SPACE=Spazio libero (byte)\: +MossDebugUtils.MSG_FREEMEM=Memoria libera (byte)\: +MossDebugUtils.MSG_FS_ROOT=File sistem radice\: +MossDebugUtils.MSG_IO_EXCEPTION=IOException in caricamento, forse inesistente? +MossDebugUtils.MSG_JAVA_PROPS=<<>>\n +MossDebugUtils.MSG_MAXMEM=Memoria massima (byte)\: +MossDebugUtils.MSG_MEM_NO_LIMIT=nessun limite +MossDebugUtils.MSG_SYS_PROPS=<<>>\n +MossDebugUtils.MSG_TOTAL_MEM=Memoria totale (byte)\: +MossDebugUtils.MSG_TOTAL_SPACE=Spazio totale (byte)\: +MossDebugUtils.MSG_USABLE_SPACE=Spazio utilizzabile (byte)\: +MossGame.CFG_LOAD_ERR=Errore nel caricamento del file di configurazione. +MossGame.DIR_OR_CFG_NOT_FOUND=Cartella del gioco o file di configurazione non trovati. +MossGame.FILE_NOT_FOUND=Il file {0} non \u00E8 stato trovato. +MossScript.[NAME]_NOT_FOUND=\ non trovato\! +MossScript.MSG_IO_EXCEPTION=IOException con lo script chiamato +MossScript.MSG_OOPS=Abbiamo per le mani una situazione estremamente inaspettata +MossScript.MSG_SCRIPT_NAMED_[NAME]=Script chiamato +MossTest.PORT_DESC=Numero della porta da usare +MossTest.RUN_STANDALONE=Eseguire come server autonomo +MossWorld.ERR_DB=E' avvenuto un errore nell'apertura della banca dati. Probabilmente non \u00E8 accessibile, su un disco pieno, o corrotta. +MossWorld.MG_SELECT_FAILURE=Non \u00E8 stato possibile inserire il seme nel generatore di mappe. +MossWorld.NO_GAME_ID=Non \u00E8 specificato lo ID del gioco. Lo ID del gioco deve essere specificato in game.xml come pincopallino dove data/games/pincopallino \u00E8 una cartella con un gioco valido. +MossWorld.NO_NETWORKING_NOW=La connettivit\u00E0 non \u00E8 completa in questa versione. +NodeManager.DESC_UNKNWN_NODE=Un pezzo sconosciuto del mondo +ScriptEnv.ERR_SCRIPT_ERR=E'' avvenuto un errore di script. Eccezione impacchettata\: {0} \n +ServerNetworkingManager.ACCEPT_THREAD=svrNetAccept +ServerNetworkingManager.CONN_THREAD_NAME=thread di connessione +ServerNetworkingManager.THREADGROUP=SvrNetGroup +PACKET_INVALID_MAGIC=E'' stato ricevuto un pacchetto con un numero magico non valido ed \u00E8 stato gettato. +SERVER_CONN_TIMEOUT=La connessione al server \u00E8 scaduta o fallita in un altro modo. +FIXME_MESSAGE=Toccato un blocco di codice che rappresenta una funzionalit\u00E0 mancante. Per favore compilate un rapporto di bug oppure ricordatelo bruscamente agli sviluppatori in un altro modo. +EVENT_PROCESS_EXCEPTION=Notato {0} nell''elaborazione di un evento di tipo {1}. Il messaggio dell''eccezione era {2}.