lots of client rework

master
rarkenin 2014-05-03 20:47:30 -04:00
parent 5987dd3473
commit a9e4e95687
28 changed files with 676 additions and 74 deletions

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<etag-cache/>

View File

@ -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.

View File

@ -10,7 +10,6 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: com.intellij:annotations:9.0.4" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-math:2.2" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.6" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.1" level="project" />
@ -45,6 +44,7 @@
<orderEntry type="library" name="Maven: log4j:log4j:1.2.15" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />
<orderEntry type="library" name="Maven: com.intellij:annotations:9.0.4" level="project" />
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.9" level="project" />
</component>
</module>

View File

@ -336,6 +336,12 @@
<artifactId>annotations</artifactId>
<version>9.0.4</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
</dependencies>
</project>

View File

@ -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"));
}
}
}

View File

@ -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<MossNetPacket> 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);
}
/**

View File

@ -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 + '!';
}
}
}

View File

@ -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
}
}

View File

@ -38,10 +38,14 @@ public class RemoteFileManager implements IFileManager {
private HashMap<String, RemoteFile> knownByName = new HashMap<>();
private HashMap<String, RemoteFile> 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);

View File

@ -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.

View File

@ -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.

View File

@ -1,4 +1,4 @@
package net.mosstest.servercore.netcommand;
package net.mosstest.netcommand;
/**
* The Class MalformedPacketException.

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -1,4 +1,4 @@
package net.mosstest.servercore.netcommand;
package net.mosstest.netcommand;
/**
* The Class ToClientCommand.

View File

@ -0,0 +1,10 @@
package net.mosstest.netcommand;
/**
* The Class ToServerCommand.
*/
public abstract class ToServerCommand {
//ignore
}

View File

@ -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();
}
}

View File

@ -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<Short> requestedScriptApiVer = new InheritableThreadLocal<Short>(){
@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<Class<? extends IMossEvent>, ArrayList<MossEventHandler>> eventHandlers;
@ -315,13 +331,13 @@ public class MossScriptEnv {
return this.fp;
}
private HashMap<Class<? extends IMossEvent>, List<MossEventHandler>> handlers = new HashMap<>();
private HashMap<Class<? extends IMossEvent>, List<WrappedHandler>> handlers = new HashMap<>();
public List<MossEventHandler> getEventHandlers(
public List<WrappedHandler> getEventHandlers(
Class<? extends IMossEvent> clazz) {
List<MossEventHandler> l = Collections.unmodifiableList(handlers.get(clazz));
List<WrappedHandler> l = Collections.unmodifiableList(handlers.get(clazz));
if (l == null) {
handlers.put(clazz, new ArrayList<MossEventHandler>());
handlers.put(clazz, new ArrayList<WrappedHandler>());
return Collections.EMPTY_LIST;
}
return l;
@ -329,14 +345,12 @@ public class MossScriptEnv {
}
public void registerHandler(MossEventHandler handler, Class<? extends IMossEvent> clazz) {
List<MossEventHandler> l = handlers.get(clazz);
List<WrappedHandler> l = handlers.get(clazz);
if (l == null) {
l = new ArrayList<MossEventHandler>();
l = new ArrayList<WrappedHandler>();
handlers.put(clazz, l);
l.add(handler);
return;
}
l.add(handler);
l.add(new WrappedHandler(handler, this.requestedScriptApiVer.get()));
}

View File

@ -26,6 +26,8 @@ public class Player {
*/
private HashMap<String, MossInventory> inventories = new HashMap<>();
public int playerId;
/**
* The name.
*/

View File

@ -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;
}
}

View File

@ -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.

View File

@ -1,5 +1,6 @@
package net.mosstest.servercore;
import net.mosstest.client.ClientNetworkingManager;
import net.mosstest.scripting.Position;
// TODO: Auto-generated Javadoc

View File

@ -1,5 +1,7 @@
package net.mosstest.servercore;
import net.mosstest.client.ClientNetworkingManager;
import java.io.IOException;

View File

@ -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;
}

View File

@ -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
* <p>
* <p/>
* Blargh.
* <p>
* <p/>
* 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<MossEventHandler> evtHandlerList = this.ev
List<WrappedHandler> 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();
}
}

View File

@ -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.

View File

@ -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()));

View File

@ -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=<<<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=<<<Java properties>>>\n
MossDebugUtils.MSG_MAXMEM=Memoria massima (byte)\:
MossDebugUtils.MSG_MEM_NO_LIMIT=nessun limite
MossDebugUtils.MSG_SYS_PROPS=<<<System properties>>>\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 <gameid>pincopallino</gameid> 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}.