Chat Tutorial in NetBeans/Text Client: Difference between revisions
Jump to navigation
Jump to search
Content deleted Content added
imported>SimonSmall →Build the Project: Added log4j.jar library |
imported>SimonSmall m →Using the marauroa project: spelling |
||
| (40 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
= Introduction = |
= Introduction = |
||
From the Design Objectives given in the Chat Tutorial, this is a text based client that runs in a command / terminal window. It is executed on the Server and establishes communications to the Server program, with no user interaction. It includes some error logging, comments and Javadoc output. |
|||
For more detail in using the NetBeans IDE, see the [[Using and configuring NetBeans]] page. |
|||
== Comments and Javadoc == |
|||
There are a number of comments in the code below, primarily added as an explanation of the code, but also added as an illustration of comments and how Javadoc can be seen in the NetBeans IDE. |
|||
= NetBeans Project = |
= NetBeans Project = |
||
| Line 11: | Line 17: | ||
== Adding the Marauroa library == |
== Adding the Marauroa library == |
||
Choose the correct way depending on if you are using the marauroa.jar file, |
Choose the correct way depending on if you are using the marauroa.jar file, or have created a marauroa project from the source code. |
||
=== Using the Jar file === |
=== Using the Jar file === |
||
Use this option unless you need to use the other methods. |
|||
Find the '''marauroa.jar''' file from the download, and copy it to the libs directory (created above) if it is not there already. Right click the '''Libraries''' branch of the server Project tree, and select '''Add Jar/Folder'''. Browse to the the libs directory for this project and select the marauroa.jar file. This will include the marauroa library with no view of the source code. |
|||
Find the '''marauroa.jar''' file from the download, and copy it to the libs directory (created above) if it is not there already. Right click the '''Libraries''' branch of the client Project tree, and select '''Add Jar/Folder'''. Browse to the the libs directory for this project and select the marauroa.jar file. This will include the marauroa library with no view of the source code. |
|||
=== Using the marauroa project === |
=== Using the marauroa project === |
||
Right click the '''Libraries''' branch of the |
Right click the '''Libraries''' branch of the client Project tree, and select '''Add Project'''. Make sure you browse to the correct file location and select the '''marauroa''' project that you created earlier. This will include your marauroa library that you built, and you can see the source code. |
||
= Additional files = |
|||
The following files |
The following files are required to extend the Marauroa engine functionality. |
||
== Test.java == |
|||
This file was created when you created the new Project. Add the following (or replace the existing) code. This is the a simple flow to test the client and server code works to give basic communication. Some simple comments are included. |
|||
<source lang="Java"> |
|||
/* |
|||
* Test class for Marauroa Chat Tutorial |
|||
* - see http://stendhalgame.org/wiki/Marauroa_Chat_Tutorial |
|||
*/ |
|||
package client; |
|||
import marauroa.common.Log4J; |
|||
import marauroa.common.game.RPObject; |
|||
/** |
|||
* Run the client to communicate with the server |
|||
*/ |
|||
public class Test { |
|||
@SuppressWarnings("SleepWhileInLoop") |
|||
private static marauroa.common.Logger logger = Log4J.getLogger(Test.class); |
|||
public static void main(String[] args) { |
|||
// flag: false to stop client |
|||
boolean cond = true; |
|||
// create the Client to handle communications |
|||
Client my = Client.get(); |
|||
try { |
|||
my.connect("localhost", 5555); |
|||
// create new account if 3rd parameter is present (email address) |
|||
if (args.length == 3) { |
|||
my.createAccount(args[0], args[1], args[2]); |
|||
} |
|||
// do log in |
|||
my.login(args[0], args[1]); |
|||
if (my.getAvailableCharacters().length == 0) { |
|||
RPObject character = new RPObject(); |
|||
my.createCharacter(args[0], character); |
|||
} |
|||
my.chooseCharacter(args[0]); |
|||
} catch (Exception e) { |
|||
cond = false; |
|||
logger.info("Login failure: " + e); |
|||
} |
|||
// connection loop (no user interaction) |
|||
int i = 0; |
|||
while (cond) { |
|||
++i; |
|||
// get and apply messages |
|||
my.loop(0); |
|||
if (i % 100 == 50) { |
|||
my.sendMessage("test" + i); |
|||
} |
|||
String s = my.popQuote(); |
|||
while (s != null) { |
|||
System.out.println(s); |
|||
s = my.popQuote(); |
|||
} |
|||
try { |
|||
Thread.sleep(100); |
|||
} catch (InterruptedException e) { |
|||
cond = false; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</source> |
|||
Close and Save the file. Note how NetBeans shows an error because it does not recognise the Client class. |
|||
== Adding Logging to the Client == |
|||
To trace errors, or to monitor which parts of a program are executed, message (log) statements can be inserted in the code, as in Test.java (above). The log4j library provides a flexible and configurable way to do this. See [[Logging in Marauroa | how this is done]] in Marauroa. |
|||
=== The logging configuration file === |
|||
To specify the logging output right-click on the '''client''' package and add a new '''Empty File'''. Give the '''File Name''' as '''log4j_client.properties'''. Add the following lines to that file: |
|||
<pre> |
|||
# Set root logging level to INFO, and create two output configurations |
|||
log4j.rootLogger=INFO, Console, File |
|||
# Paste all log entries to the console |
|||
log4j.appender.Console=org.apache.log4j.ConsoleAppender |
|||
log4j.appender.Console.layout=org.apache.log4j.PatternLayout |
|||
log4j.appender.Console.layout.ConversionPattern=%d{ISO8601} [%t] %-5p %c - %m%n |
|||
# Paste all log entries to a daily log file |
|||
log4j.appender.File=org.apache.log4j.DailyRollingFileAppender |
|||
log4j.appender.File.File=log/client.log |
|||
log4j.appender.File.layout=org.apache.log4j.PatternLayout |
|||
log4j.appender.File.layout.ConversionPattern=%d{ISO8601} [%t] %-5p %c - %m%n |
|||
# Set priority to warning messages and above, disabling debug and info messages |
|||
log4j.logger.marauroa.client=WARN |
|||
</pre> |
|||
Close and Save the file. |
|||
== Adding the log4j library == |
|||
Although this does not create a compile error it will create an error when you run the Text Client. |
|||
Copy the '''log4j.jar''' file from the downloaded source files to the '''libs''' directory (created above). Right click the '''Libraries''' branch of the server Project tree, and select '''Add Jar/Folder'''. Browse to the the libs directory for this project and select the log4j.jar file. |
|||
== Client.java == |
|||
This file extends the Marauroa ClientFramework class, to provide methods that give the required responses when these actions are carried out. |
|||
Right-click on the '''client''' package and add a new '''Java Class'''. Give the '''Class Name''' as '''Client'''. Replace the template code with the following code: |
Right-click on the '''client''' package and add a new '''Java Class'''. Give the '''Class Name''' as '''Client'''. Replace the template code with the following code: |
||
| Line 31: | Line 158: | ||
<source lang="Java"> |
<source lang="Java"> |
||
/* |
/* |
||
* Client class for Marauroa Chat Tutorial |
|||
* |
|||
* - see http://stendhalgame.org/wiki/Marauroa_Chat_Tutorial |
|||
*/ |
*/ |
||
| Line 43: | Line 171: | ||
import marauroa.client.net.IPerceptionListener; |
import marauroa.client.net.IPerceptionListener; |
||
import marauroa.client.net.PerceptionHandler; |
import marauroa.client.net.PerceptionHandler; |
||
import marauroa.common.Log4J; |
|||
import marauroa.common.game.RPAction; |
import marauroa.common.game.RPAction; |
||
import marauroa.common.game.RPObject; |
import marauroa.common.game.RPObject; |
||
| Line 49: | Line 178: | ||
/** |
/** |
||
* Handle the connection to the game Server |
|||
* |
|||
*/ |
*/ |
||
public class Client extends ClientFramework { |
public class Client extends ClientFramework { |
||
private PerceptionHandler handler; |
|||
protected static Client client; |
|||
private Map<RPObject.ID, RPObject> world_objects; |
|||
private String[] available_characters; |
|||
private List<String> quotes = new ArrayList<String>(); |
|||
public static Client get() { |
|||
if (client == null) { |
|||
client = new Client(); |
|||
} |
|||
return client; |
|||
} |
|||
protected Client() { |
|||
super("log4j.properties"); |
|||
world_objects = new HashMap<RPObject.ID, RPObject>(); |
|||
handler = new PerceptionHandler(new PerceptionListener()); |
|||
} |
|||
public String[] GetAvailableCharacters() { |
|||
return available_characters; |
|||
} |
|||
String popQuote() { |
|||
if (quotes.isEmpty()) { |
|||
return null; |
|||
} |
|||
String result = quotes.get(0); |
|||
quotes.remove(0); |
|||
return result; |
|||
} |
|||
public void SendMessage(String text) { |
|||
RPAction action; |
|||
action = new RPAction(); |
|||
action.put("type", "chat"); |
|||
action.put("text", text); |
|||
send(action); |
|||
} |
|||
@Override |
|||
protected void onPerception(MessageS2CPerception message) { |
|||
try { |
|||
handler.apply(message, world_objects); |
|||
} catch (java.lang.Exception e) { |
|||
// Something weird happened while applying perception |
|||
} |
|||
} |
|||
protected static Client client; |
|||
@Override |
|||
protected List<TransferContent> onTransferREQ(List<TransferContent> items) { |
|||
return items; |
|||
} |
|||
private String[] available_characters; |
|||
@Override |
|||
protected void onTransfer(List<TransferContent> items) { |
|||
} |
|||
private PerceptionHandler handler; |
|||
@Override |
|||
protected void onAvailableCharacters(String[] characters) { |
|||
available_characters = characters; |
|||
} |
|||
private static marauroa.common.Logger logger = Log4J.getLogger(Client.class); |
|||
@Override |
|||
protected void onServerInfo(String[] info) { |
|||
for (String s : info) { |
|||
quotes.add(s); |
|||
} |
|||
} |
|||
private List<String> quotes = new ArrayList<String>(); |
|||
@Override |
|||
protected String getGameName() { |
|||
return "Chat"; |
|||
} |
|||
private Map<RPObject.ID, RPObject> world_objects; |
|||
@Override |
|||
protected String getVersionNumber() { |
|||
return "0.1"; |
|||
} |
|||
/** |
|||
@Override |
|||
* singleton constructor - logger, objects and interface handler |
|||
protected void onPreviousLogins(List<String> previousLogins) { |
|||
*/ |
|||
protected Client() { |
|||
super("client/log4j_client.properties"); |
|||
world_objects = new HashMap<RPObject.ID, RPObject>(); |
|||
handler = new PerceptionHandler(new PerceptionListener()); |
|||
} |
|||
public static Client get() { |
|||
class PerceptionListener implements IPerceptionListener { |
|||
if (client == null) { |
|||
client = new Client(); |
|||
} |
|||
return client; |
|||
} |
|||
public String[] getAvailableCharacters() { |
|||
@Override |
|||
return available_characters; |
|||
public boolean onAdded(RPObject object) { |
|||
if (object.has("text")) { |
|||
quotes.add("*" + object.get("from") + "* : " + object.get("text")); |
|||
} |
|||
return false; |
|||
} |
} |
||
/** |
|||
* take the next message from the queue |
|||
public boolean onModifiedAdded(RPObject object, RPObject changes) { |
|||
*/ |
|||
public String popQuote() { |
|||
if (quotes.isEmpty()) { |
|||
return null; |
|||
} |
|||
String result = quotes.get(0); |
|||
quotes.remove(0); |
|||
return result; |
|||
} |
} |
||
/** |
|||
* send the message (as an action) to the server |
|||
public boolean onModifiedDeleted(RPObject object, RPObject changes) { |
|||
*/ |
|||
public void sendMessage(String text) { |
|||
RPAction action; |
|||
action = new RPAction(); |
|||
action.put("type", "chat"); |
|||
action.put("text", text); |
|||
send(action); |
|||
} |
} |
||
/** |
|||
* process message from server |
|||
*/ |
|||
@Override |
@Override |
||
protected void onPerception(MessageS2CPerception message) { |
|||
public boolean onDeleted(RPObject object) { |
|||
try { |
|||
handler.apply(message, world_objects); |
|||
} catch (java.lang.Exception e) { |
|||
// Something weird happened while applying perception |
|||
logger.warn("Applying perception: " + e); |
|||
} |
|||
} |
} |
||
/** |
|||
* request transfer of content from server |
|||
*/ |
|||
@Override |
@Override |
||
protected List<TransferContent> onTransferREQ(List<TransferContent> items) { |
|||
public boolean onMyRPObject(RPObject added, RPObject deleted) { |
|||
return |
return items; |
||
} |
} |
||
/** |
|||
* process received transfer of content from server |
|||
*/ |
|||
@Override |
@Override |
||
protected void onTransfer(List<TransferContent> items) { |
|||
} |
} |
||
/** |
|||
* on receipt of character list from server, save it |
|||
*/ |
|||
@Override |
@Override |
||
protected void onAvailableCharacters(String[] characters) { |
|||
available_characters = characters; |
|||
} |
} |
||
/** |
|||
* on receipt of server info, store in message queue |
|||
*/ |
|||
@Override |
@Override |
||
protected void onServerInfo(String[] info) { |
|||
public void onException(Exception e, marauroa.common.net.message.MessageS2CPerception perception) { |
|||
for (String s : info) { |
|||
e.printStackTrace(); |
|||
quotes.add(s); |
|||
} |
|||
} |
} |
||
/** |
|||
* use to check that this client matches the server |
|||
*/ |
|||
@Override |
@Override |
||
protected String getGameName() { |
|||
return |
return "Chat"; |
||
} |
} |
||
/** |
|||
public void onPerceptionBegin(byte type, int timestamp) { |
|||
* use to check that this client version matches the server version |
|||
*/ |
|||
@Override |
|||
protected String getVersionNumber() { |
|||
return "0.1"; |
|||
} |
} |
||
/** |
|||
public void onPerceptionEnd(byte type, int timestamp) { |
|||
* previous logins not used |
|||
*/ |
|||
@Override |
|||
protected void onPreviousLogins(List<String> previousLogins) { |
|||
} |
} |
||
} |
|||
} |
|||
</source> |
|||
/** |
|||
Close and Save the file. |
|||
* apply perceptions: add, change or delete objects |
|||
*/ |
|||
class PerceptionListener implements IPerceptionListener { |
|||
/** |
|||
=== Test.java === |
|||
* clear world on sync perceptions |
|||
*/ |
|||
@Override |
|||
public boolean onClear() { |
|||
return false; |
|||
} |
|||
/** |
|||
This file was created when you created the new Project. Add the following (or replace the existing) code: |
|||
* get new messages from server; add to message queue |
|||
*/ |
|||
@Override |
|||
public boolean onAdded(RPObject object) { |
|||
if (object.has("text")) { |
|||
quotes.add("*" + object.get("from") + "* : " + object.get("text")); |
|||
} |
|||
return false; |
|||
} |
|||
/** |
|||
<source lang="Java"> |
|||
* server has deleted an object; client does not need to do anything |
|||
/* |
|||
*/ |
|||
* |
|||
@Override |
|||
*/ |
|||
public boolean onDeleted(RPObject object) { |
|||
return false; |
|||
} |
|||
/** |
|||
package client; |
|||
* server has modified an object; client does not need to do anything |
|||
*/ |
|||
@Override |
|||
public boolean onModifiedAdded(RPObject object, RPObject changes) { |
|||
return false; |
|||
} |
|||
/** |
|||
import marauroa.common.game.RPObject; |
|||
* server has modified an object; client does not need to do anything |
|||
*/ |
|||
@Override |
|||
public boolean onModifiedDeleted(RPObject object, RPObject changes) { |
|||
return false; |
|||
} |
|||
/** |
/** |
||
* player avatar is to be processed |
|||
* |
|||
*/ |
|||
*/ |
|||
@Override |
|||
public class Test { |
|||
public boolean onMyRPObject(RPObject added, RPObject deleted) { |
|||
@SuppressWarnings("SleepWhileInLoop") |
|||
return false; |
|||
public static void main(String[] args) { |
|||
} |
|||
Client my = Client.get(); |
|||
/** |
|||
* client cannot process perception; exit client |
|||
my.connect("localhost", 5555); |
|||
*/ |
|||
@Override |
|||
my.createAccount(args[0], args[1], args[2]); |
|||
public void onException(Exception e, marauroa.common.net.message.MessageS2CPerception perception) { |
|||
} |
|||
logger.warn("Exit on exception: " + e + " : " + perception.toString()); |
|||
my.login(args[0], args[1]); |
|||
e.printStackTrace(); |
|||
if (my.GetAvailableCharacters().length == 0) { |
|||
System.exit(-1); |
|||
} |
|||
my.createCharacter(args[0], character); |
|||
} |
|||
@Override |
|||
my.chooseCharacter(args[0]); |
|||
public void onPerceptionBegin(byte type, int timestamp) { |
|||
} catch (Exception e) { |
|||
} |
|||
@Override |
|||
public void onPerceptionEnd(byte type, int timestamp) { |
|||
} |
|||
@Override |
|||
public void onSynced() { |
|||
} |
|||
@Override |
|||
public void onUnsynced() { |
|||
} |
|||
} |
} |
||
int i = 0; |
|||
while (cond) { |
|||
++i; |
|||
my.loop(0); |
|||
if (i % 100 == 50) { |
|||
my.SendMessage("test" + i); |
|||
} |
|||
String s = my.popQuote(); |
|||
while (s != null) { |
|||
System.out.println(s); |
|||
s = my.popQuote(); |
|||
} |
|||
try { |
|||
Thread.sleep(100); |
|||
} catch (InterruptedException e) { |
|||
cond = false; |
|||
} |
|||
} |
|||
} |
|||
} |
} |
||
</source> |
</source> |
||
| Line 255: | Line 393: | ||
Close and Save the file. |
Close and Save the file. |
||
= Build the Project = |
|||
If there are no errors in the package, there is one last thing to do. Although this does not create a compile error it will create an error when you run the Text Client. |
|||
Copy the '''log4j.jar''' file from the downloaded source files to the '''libs''' directory (created above). Right click the '''Libraries''' branch of the server Project tree, and select '''Add Jar/Folder'''. Browse to the the libs directory for this project and select the log4j.jar file. |
|||
Finally, select '''Run''', '''Build Main Project''' from the NetBeans menu bar. This will create '''client.jar''' in the '''dist''' directory, and copy the jar files from the libs directory to the '''lib''' sub-directory of dist. |
Finally, select '''Run''', '''Build Main Project''' from the NetBeans menu bar. This will create '''client.jar''' in the '''dist''' directory, and copy the jar files from the libs directory to the '''lib''' sub-directory of dist. |
||
= Completion = |
|||
You have created the two class files and compiled them into a java library. Now you can follow the deployment instructions for preparing and testing your |
You have created the two class files and compiled them into a java library. Now you should create the [[Chat Tutorial in NetBeans/Server|server files]], then you can follow the [[Chat Tutorial in NetBeans/Deploy Text Client|deployment instructions]] for preparing and testing your code. |
||
[[Category:NetBeans]] |
[[Category:NetBeans]] |
||