 |
Crossfire JXClient, Trunk
|
Go to the documentation of this file.
23 package com.realtime.crossfire.jxclient.server.crossfire;
44 import java.io.BufferedReader;
45 import java.io.ByteArrayInputStream;
46 import java.io.IOException;
47 import java.io.InputStreamReader;
48 import java.nio.Buffer;
49 import java.nio.BufferUnderflowException;
50 import java.nio.ByteBuffer;
51 import java.nio.ByteOrder;
52 import java.nio.charset.StandardCharsets;
53 import java.util.ArrayDeque;
54 import java.util.ArrayList;
55 import java.util.Arrays;
56 import java.util.Collection;
57 import java.util.Deque;
58 import java.util.LinkedHashMap;
59 import java.util.List;
61 import java.util.regex.Pattern;
62 import org.jetbrains.annotations.NotNull;
63 import org.jetbrains.annotations.Nullable;
91 private static final Pattern
PATTERN_DOT = Pattern.compile(
":");
97 private static final Pattern
PATTERN_BAR = Pattern.compile(
"\\|+");
242 private static final byte @NotNull []
ACCOUNT_LOGIN_PREFIX =
"accountlogin ".getBytes(StandardCharsets.US_ASCII);
247 private static final byte @NotNull []
ACCOUNT_PLAY_PREFIX =
"accountplay ".getBytes(StandardCharsets.US_ASCII);
257 private static final byte @NotNull []
ACCOUNT_NEW_PREFIX =
"accountnew ".getBytes(StandardCharsets.US_ASCII);
267 private static final byte @NotNull []
CREATE_PLAYER_PREFIX =
"createplayer ".getBytes(StandardCharsets.US_ASCII);
272 private static final byte @NotNull []
ADDME_PREFIX =
"addme ".getBytes(StandardCharsets.US_ASCII);
277 private static final byte @NotNull []
APPLY_PREFIX =
"apply ".getBytes(StandardCharsets.US_ASCII);
282 private static final byte @NotNull []
ASKFACE_PREFIX =
"askface ".getBytes(StandardCharsets.US_ASCII);
287 private static final byte @NotNull []
EXAMINE_PREFIX =
"examine ".getBytes(StandardCharsets.US_ASCII);
292 private static final byte @NotNull []
LOCK_PREFIX =
"lock ".getBytes(StandardCharsets.US_ASCII);
297 private static final byte @NotNull []
LOOKAT_PREFIX =
"lookat ".getBytes(StandardCharsets.US_ASCII);
302 private static final byte @NotNull []
MARK_PREFIX =
"mark ".getBytes(StandardCharsets.US_ASCII);
307 private static final byte @NotNull []
MOVE_PREFIX =
"move ".getBytes(StandardCharsets.US_ASCII);
312 private static final byte @NotNull []
NCOM_PREFIX =
"ncom ".getBytes(StandardCharsets.US_ASCII);
317 private static final byte @NotNull []
REPLY_PREFIX =
"reply ".getBytes(StandardCharsets.US_ASCII);
322 private static final byte @NotNull []
REQUESTINFO_PREFIX =
"requestinfo ".getBytes(StandardCharsets.US_ASCII);
327 private static final byte @NotNull []
SETUP_PREFIX =
"setup".getBytes(StandardCharsets.US_ASCII);
337 private static final byte @NotNull []
VERSION_PREFIX =
"version ".getBytes(StandardCharsets.US_ASCII);
376 private final Object sync =
new Object();
379 public void newMap(
final int mapWidth,
final int mapHeight) {
384 public Object mapBegin() {
389 public void mapClear(
final int x,
final int y) {
393 public void mapDarkness(
final int x,
final int y,
final int darkness) {
397 public void mapFace(@NotNull
final Location location,
final int faceNum) {
401 public void mapAnimation(@NotNull
final Location location,
final int animationNum,
final int animationType) {
405 public void mapAnimationSpeed(@NotNull
final Location location,
final int animationSpeed) {
409 public void mapSmooth(@NotNull
final Location location,
final int smooth) {
413 public void mapScroll(
final int dx,
final int dy) {
417 public void magicMap(
final int x,
final int y,
final byte @NotNull [] @NotNull [] data) {
421 public void mapEnd() {
458 @SuppressWarnings(
"FieldCanBeLocal")
462 public void connecting() {
482 public void disconnected(@NotNull
final String reason) {
520 public void stop() throws InterruptedException {
560 if (
packet.get() !=
'c') {
563 if (
packet.get() !=
'o') {
566 if (
packet.get() !=
'u') {
569 if (
packet.get() !=
'n') {
572 if (
packet.get() !=
't') {
575 if (
packet.get() !=
'p') {
578 if (
packet.get() !=
'l') {
581 if (
packet.get() !=
'a') {
584 if (
packet.get() !=
'y') {
587 if (
packet.get() !=
'e') {
590 if (
packet.get() !=
'r') {
593 if (
packet.get() !=
's') {
596 if (
packet.get() !=
' ') {
603 if (
packet.get() !=
'd') {
608 if (
packet.get() !=
'n') {
611 if (
packet.get() !=
'o') {
614 if (
packet.get() !=
'w') {
617 if (
packet.get() !=
'l') {
620 if (
packet.get() !=
'e') {
623 if (
packet.get() !=
'd') {
626 if (
packet.get() !=
'g') {
629 if (
packet.get() !=
'e') {
632 if (
packet.get() !=
' ') {
639 if (
packet.get() !=
'e') {
642 if (
packet.get() !=
'_') {
647 if (
packet.get() !=
'a') {
650 if (
packet.get() !=
'i') {
653 if (
packet.get() !=
'l') {
656 if (
packet.get() !=
'e') {
659 if (
packet.get() !=
'd') {
662 if (
packet.hasRemaining()) {
669 if (
packet.get() !=
'u') {
672 if (
packet.get() !=
'c') {
675 if (
packet.get() !=
'c') {
678 if (
packet.get() !=
'e') {
681 if (
packet.get() !=
's') {
684 if (
packet.get() !=
's') {
687 if (
packet.hasRemaining()) {
696 if (
packet.get() !=
'u') {
699 if (
packet.get() !=
'e') {
702 if (
packet.get() !=
's') {
705 if (
packet.get() !=
't') {
708 if (
packet.get() !=
' ') {
715 if (
packet.get() !=
'p') {
718 if (
packet.get() !=
'e') {
721 if (
packet.get() !=
'l') {
724 if (
packet.get() !=
'l') {
727 if (
packet.get() !=
' ') {
736 if (
packet.get() !=
'i') {
739 if (
packet.get() !=
'm') {
742 if (
packet.get() !=
' ') {
751 if (
packet.get() !=
'o') {
754 if (
packet.get() !=
'm') {
757 if (
packet.get() !=
'c') {
760 if (
packet.get() !=
' ') {
769 if (
packet.get() !=
'l') {
776 if (
packet.get() !=
'v') {
779 if (
packet.get() !=
' ') {
786 if (
packet.get() !=
'e') {
789 if (
packet.get() !=
'm') {
792 if (
packet.get() !=
' ') {
801 if (
packet.get() !=
'p') {
804 if (
packet.get() !=
'e') {
807 if (
packet.get() !=
'l') {
810 if (
packet.get() !=
'l') {
813 if (
packet.get() !=
' ') {
822 if (
packet.get() !=
'a') {
825 if (
packet.get() !=
'w') {
830 if (
packet.get() !=
'x') {
833 if (
packet.get() !=
't') {
836 if (
packet.get() !=
'i') {
839 if (
packet.get() !=
'n') {
842 if (
packet.get() !=
'f') {
845 if (
packet.get() !=
'o') {
848 if (
packet.get() !=
' ') {
855 if (
packet.get() !=
'n') {
858 if (
packet.get() !=
'f') {
861 if (
packet.get() !=
'o') {
864 if (
packet.get() !=
' ') {
875 if (
packet.get() !=
'x') {
878 if (
packet.get() !=
't') {
881 if (
packet.get() !=
'e') {
884 if (
packet.get() !=
'n') {
887 if (
packet.get() !=
'd') {
890 if (
packet.get() !=
'e') {
893 if (
packet.get() !=
'd') {
898 if (
packet.get() !=
'n') {
901 if (
packet.get() !=
'f') {
904 if (
packet.get() !=
'o') {
907 if (
packet.get() !=
'S') {
910 if (
packet.get() !=
'e') {
913 if (
packet.get() !=
't') {
916 if (
packet.get() !=
' ') {
923 if (
packet.get() !=
'e') {
926 if (
packet.get() !=
'x') {
929 if (
packet.get() !=
't') {
932 if (
packet.get() !=
'S') {
935 if (
packet.get() !=
'e') {
938 if (
packet.get() !=
't') {
941 if (
packet.get() !=
' ') {
950 if (
packet.get() !=
'a') {
955 if (
packet.get() !=
'e') {
958 if (
packet.get() !=
'2') {
961 if (
packet.get() !=
' ') {
968 if (
packet.get() !=
'l') {
971 if (
packet.get() !=
'u') {
974 if (
packet.get() !=
'r') {
977 if (
packet.get() !=
'e') {
980 if (
packet.get() !=
' ') {
989 if (
packet.get() !=
'o') {
992 if (
packet.get() !=
'o') {
995 if (
packet.get() !=
'd') {
998 if (
packet.get() !=
'b') {
1001 if (
packet.get() !=
'y') {
1004 if (
packet.get() !=
'e') {
1007 if (
packet.get() !=
' ') {
1016 if (
packet.get() !=
'a') {
1019 if (
packet.get() !=
'g') {
1022 if (
packet.get() !=
'e') {
1025 if (
packet.get() !=
'2') {
1028 if (
packet.get() !=
' ') {
1035 if (
packet.get() !=
'e') {
1038 if (
packet.get() !=
'm') {
1041 if (
packet.get() !=
'2') {
1044 if (
packet.get() !=
' ') {
1057 if (
packet.get() !=
'i') {
1060 if (
packet.get() !=
'c') {
1063 if (
packet.get() !=
'm') {
1066 if (
packet.get() !=
'a') {
1069 if (
packet.get() !=
'p') {
1072 if (
packet.get() !=
' ') {
1081 if (
packet.get() !=
' ') {
1088 if (
packet.get() !=
'x') {
1091 if (
packet.get() !=
't') {
1094 if (
packet.get() !=
'e') {
1097 if (
packet.get() !=
'n') {
1100 if (
packet.get() !=
'd') {
1103 if (
packet.get() !=
'e') {
1106 if (
packet.get() !=
'd') {
1109 if (
packet.get() !=
' ') {
1120 if (
packet.get() !=
's') {
1123 if (
packet.get() !=
'i') {
1126 if (
packet.get() !=
'c') {
1129 if (
packet.get() !=
' ') {
1138 if (
packet.get() !=
'e') {
1141 if (
packet.get() !=
'w') {
1144 if (
packet.get() !=
'm') {
1147 if (
packet.get() !=
'a') {
1150 if (
packet.get() !=
'p') {
1159 if (
packet.get() !=
'c') {
1162 if (
packet.get() !=
'k') {
1165 if (
packet.get() !=
'u') {
1168 if (
packet.get() !=
'p') {
1171 if (
packet.get() !=
' ') {
1178 if (
packet.get() !=
'a') {
1181 if (
packet.get() !=
'y') {
1184 if (
packet.get() !=
'e') {
1187 if (
packet.get() !=
'r') {
1190 if (
packet.get() !=
' ') {
1199 if (
packet.get() !=
'u') {
1202 if (
packet.get() !=
'e') {
1205 if (
packet.get() !=
'r') {
1208 if (
packet.get() !=
'y') {
1211 if (
packet.get() !=
' ') {
1218 if (
packet.get() !=
'e') {
1221 if (
packet.get() !=
'p') {
1224 if (
packet.get() !=
'l') {
1227 if (
packet.get() !=
'y') {
1230 if (
packet.get() !=
'i') {
1233 if (
packet.get() !=
'n') {
1236 if (
packet.get() !=
'f') {
1239 if (
packet.get() !=
'o') {
1242 if (
packet.get() !=
' ') {
1251 if (
packet.get() !=
't') {
1254 if (
packet.get() !=
'u') {
1257 if (
packet.get() !=
'p') {
1260 if (
packet.get() !=
' ') {
1267 if (
packet.get() !=
'o') {
1270 if (
packet.get() !=
'o') {
1273 if (
packet.get() !=
't') {
1276 if (
packet.get() !=
'h') {
1279 if (
packet.get() !=
' ') {
1286 if (
packet.get() !=
'u') {
1289 if (
packet.get() !=
'n') {
1292 if (
packet.get() !=
'd') {
1301 if (
packet.get() !=
' ') {
1310 if (
packet.get() !=
'a') {
1313 if (
packet.get() !=
't') {
1316 if (
packet.get() !=
's') {
1319 if (
packet.get() !=
' ') {
1328 if (
packet.get() !=
'i') {
1331 if (
packet.get() !=
'c') {
1334 if (
packet.get() !=
'k') {
1337 if (
packet.get() !=
' ') {
1344 if (
packet.get() !=
'p') {
1347 if (
packet.get() !=
'd') {
1352 if (
packet.get() !=
't') {
1355 if (
packet.get() !=
'e') {
1358 if (
packet.get() !=
'm') {
1361 if (
packet.get() !=
' ') {
1368 if (
packet.get() !=
'u') {
1371 if (
packet.get() !=
'e') {
1374 if (
packet.get() !=
's') {
1377 if (
packet.get() !=
't') {
1380 if (
packet.get() !=
' ') {
1387 if (
packet.get() !=
'p') {
1390 if (
packet.get() !=
'e') {
1393 if (
packet.get() !=
'l') {
1396 if (
packet.get() !=
'l') {
1399 if (
packet.get() !=
' ') {
1408 if (
packet.get() !=
'e') {
1411 if (
packet.get() !=
'r') {
1414 if (
packet.get() !=
's') {
1417 if (
packet.get() !=
'i') {
1420 if (
packet.get() !=
'o') {
1423 if (
packet.get() !=
'n') {
1426 if (
packet.get() !=
' ') {
1432 }
catch (
final IllegalArgumentException ex) {
1436 }
catch (
final BufferUnderflowException ex) {
1440 }
catch (
final ArrayIndexOutOfBoundsException ex) {
1444 }
catch (
final StringIndexOutOfBoundsException ex) {
1455 ((Buffer)
packet).position(0);
1457 for (cmdLen = 0; cmdLen <
packet.limit(); cmdLen++) {
1458 final byte ch =
packet.get(cmdLen);
1459 if ((ch&0xFF) <= 0x20 || (ch&0xFF) >= 0x80) {
1480 if (lenType == 0xFF) {
1484 final int len = (lenType>>5)&7;
1485 final int type = lenType&31;
1580 }
else if (len == 4) {
1582 }
else if (len != 2) {
1688 System.err.println(
"Server responded with replyinfo "+infoType+
" when expecting no replyinfo");
1690 System.err.println(
"Server responded with replyinfo "+infoType+
" when expecting replyinfo "+
sendingRequestInfo.getFirst());
1723 case "knowledge_info":
1752 System.err.println(
"Ignoring unexpected replyinfo type '"+infoType+
"'.");
1773 final byte[] data =
new byte[
packet.remaining()];
1775 try (ByteArrayInputStream is =
new ByteArrayInputStream(data)) {
1776 try (InputStreamReader isr =
new InputStreamReader(is,
UTF8)) {
1777 try (BufferedReader d =
new BufferedReader(isr)) {
1778 final String info = d.readLine();
1780 throw new IOException(
"Truncated parameter in image_info");
1782 final int nrPics = Integer.parseInt(info);
1799 final byte[] data =
new byte[
packet.remaining()];
1801 try (ByteArrayInputStream is =
new ByteArrayInputStream(data)) {
1802 try (InputStreamReader isr =
new InputStreamReader(is,
UTF8)) {
1803 try (BufferedReader d =
new BufferedReader(isr)) {
1805 final CharSequence r = d.readLine();
1811 if (sk.length < 2 || sk.length > 3) {
1812 System.err.println(
"Ignoring skill definition for invalid skill: "+r+
".");
1818 skillId = Integer.parseInt(sk[0]);
1819 }
catch (
final NumberFormatException ignored) {
1820 System.err.println(
"Ignoring skill definition for invalid skill: "+r+
".");
1825 System.err.println(
"Ignoring skill definition for invalid skill id "+skillId+
": "+r+
".");
1830 if (sk.length > 2) {
1832 face = Integer.parseInt(sk[2]);
1833 }
catch (
final NumberFormatException ignored) {
1834 System.err.println(
"Ignoring skill definition for invalid face: "+r+
".");
1853 while (
packet.remaining() >= 2) {
1854 final short skillIndex =
packet.getShort();
1855 if (skillIndex == 0) {
1856 if (
packet.hasRemaining()) {
1857 System.err.println(
"Ignoring excess data at the of skill_extra");
1861 final short len =
packet.getShort();
1876 final long[] expTable =
new long[numLevels];
1877 for (
int level = 1; level < numLevels; level++) {
1880 if (
packet.hasRemaining()) {
1881 System.err.println(
"Ignoring excess data at end of exp_table");
1897 final byte[] data =
new byte[
packet.remaining()];
1899 try (ByteArrayInputStream is =
new ByteArrayInputStream(data)) {
1900 try (InputStreamReader isr =
new InputStreamReader(is,
UTF8)) {
1901 try (BufferedReader d =
new BufferedReader(isr)) {
1903 final CharSequence r = d.readLine();
1909 if (sk.length != 4) {
1910 System.err.println(
"Ignoring knowledge definition for invalid knowledge: "+r+
".");
1916 face = Integer.parseInt(sk[2]);
1917 }
catch (
final NumberFormatException ignored) {
1918 System.err.println(
"Ignoring knowledge definition for invalid face: "+r+
".");
1938 while (
packet.hasRemaining()) {
1970 System.err.println(
"Ignoring startingmap type "+type);
1993 for (String race : races) {
2015 for (String class_ : classes) {
2031 while (
packet.hasRemaining()) {
2051 System.err.println(
"Ignoring race_info type "+type);
2073 while (
packet.hasRemaining()) {
2079 if (tokens.length != 3) {
2082 final String typeString = tokens[0];
2083 final String variableName = tokens[1];
2084 final String values = tokens[2];
2085 switch (typeString) {
2122 if (variableName.equals(
"race")) {
2123 if (!values.equals(
"requestinfo")) {
2126 newCharInfoBuilder.setRaceChoice();
2127 }
else if (variableName.equals(
"class")) {
2128 if (!values.equals(
"requestinfo")) {
2131 newCharInfoBuilder.setClassChoice();
2132 }
else if (variableName.equals(
"startingmap")) {
2133 if (!values.equals(
"requestinfo")) {
2136 newCharInfoBuilder.setStartingMapChoice();
2137 }
else if (!required) {
2138 System.err.println(
"unknown variable name '"+variableName+
"' in replyinfo newcharinfo");
2152 switch (variableName) {
2156 points = Integer.parseInt(values);
2157 }
catch (
final NumberFormatException ignored) {
2158 throw new UnknownCommandException(
"'"+variableName+
"' variable in replyinfo newcharinfo has invalid value '"+values+
"'.");
2160 newCharInfoBuilder.setPoints(points);
2165 if (tmp.length != 2) {
2166 throw new UnknownCommandException(
"'"+variableName+
"' variable in replyinfo newcharinfo has invalid value '"+values+
"'.");
2171 minValue = Integer.parseInt(tmp[0]);
2172 maxValue = Integer.parseInt(tmp[1]);
2173 }
catch (
final NumberFormatException ignored) {
2174 throw new UnknownCommandException(
"'"+variableName+
"' variable in replyinfo newcharinfo has invalid value '"+values+
"'.");
2176 newCharInfoBuilder.setStatRange(minValue, maxValue);
2180 newCharInfoBuilder.setStatNames(
PATTERN_SPACE.split(values));
2194 System.err.println(
"ignoring informational "+variableName+
"="+values+
" in replyinfo newcharinfo");
2205 while (
packet.hasRemaining()) {
2256 rb.setStatAdjustment(stat, int2Param);
2269 rb.setStatAdjustment(stat, int4Param);
2274 rb.setStatAdjustment(stat, int8Param);
2281 System.err.println(
"replyinfo race/class_info: string stat "+stat+
" not implemented");
2287 rb.setStatAdjustment(stat, int2Param2);
2291 System.err.println(
"replyinfo race/class_info: skill stat "+stat+
" not implemented");
2313 final Map<String, String> choices =
new LinkedHashMap<>();
2314 choices.put(archName, archDesc);
2317 if (archNameLength == 0) {
2322 choices.put(archName2, archDesc2);
2324 rb.addChoice(
new Choice(choiceName, choiceDescription, choices));
2341 for (
int count = 0; count < total; count++) {
2348 if (
packet.hasRemaining()) {
2367 if (!
packet.hasRemaining()) {
2420 return accountPlayerBuilder.finish();
2460 while (
packet.hasRemaining()) {
2469 final String step = stepLength > 0 ?
getString(
packet, stepLength) :
"";
2483 while (
packet.hasRemaining()) {
2503 while (
packet.hasRemaining()) {
2518 debugProtocol.
debugProtocolWrite(
"recv addspell tag="+tag+
" lvl="+level+
" time="+castingTime+
" sp="+mana+
" gr="+grace+
" dam="+damage+
" skill="+skill+
" path="+path+
" face="+face+
" name="+name+
" msg="+message);
2520 model.
getSpellsManager().
addSpell(tag, level, castingTime, mana, grace, damage, skill, path, face, name, message);
2533 final int[] faces =
new int[
packet.remaining()/2];
2534 if (faces.length <= 0) {
2538 if (
packet.hasRemaining()) {
2544 if ((num&~0x1FFF) != 0) {
2549 final StringBuilder sb =
new StringBuilder();
2553 for (
final int face : faces) {
2557 return sb.toString();
2569 if (
packet.hasRemaining()) {
2588 }
while (
packet.hasRemaining());
2589 if (
packet.hasRemaining()) {
2596 final int tag0 = tag;
2606 final int[] tags =
new int[
packet.remaining()/4];
2608 if (
packet.hasRemaining()) {
2616 final StringBuilder sb =
new StringBuilder();
2617 for (
final int tag : tags) {
2621 return sb.isEmpty() ?
"" : sb.substring(1);
2632 if (
packet.hasRemaining()) {
2671 final int color0 = color;
2672 final int type0 = type;
2673 final int subtype0 = subtype;
2694 final int color0 = color;
2704 final int startPos =
packet.position();
2714 }
while (
packet.hasRemaining());
2724 final int startPos =
packet.position();
2733 if (!
packet.hasRemaining()) {
2763 final String command;
2764 final String message;
2765 final int idx = full.indexOf(
' ');
2770 command = full.substring(0, idx);
2771 message = full.substring(idx+1);
2785 if (
packet.hasRemaining()) {
2804 if (
packet.remaining() != len) {
2807 final int faceDataPosition =
packet.position();
2811 ((Buffer)
packet).position(faceDataPosition);
2812 final byte[] data =
new byte[
packet.remaining()];
2815 listener.faceReceived(faceNum, faceSetNum, data);
2827 while (
packet.hasRemaining()) {
2834 final String name = names[0].intern();
2835 final String namePl = names.length < 2 ? name : names[1].intern();
2841 debugProtocol.
debugProtocolWrite(
"recv item2 location="+location+
" tag="+tag+
" flags="+flags+
" weight="+weight+
" face="+faceNum+
" name="+name+
" name_pl="+namePl+
" anim="+anim+
" anim_speed="+animSpeed+
" nrof="+nrof+
" type="+type);
2843 fireAddItemReceived(location, tag, flags, weight, faceNum, name, namePl, anim, animSpeed, nrof, type);
2845 if (
packet.hasRemaining()) {
2857 final boolean widthSign =
packet.get(
packet.position()) ==
'-';
2870 final boolean heightSign =
packet.get(
packet.position()) ==
'-';
2883 final boolean pxSign =
packet.get(
packet.position()) ==
'-';
2896 final boolean pySign =
packet.get(
packet.position()) ==
'-';
2912 if (
packet.remaining() != width*height) {
2916 final byte[][] data =
new byte[height][width];
2917 for (
int y = 0; y < height; y++) {
2939 while (
packet.hasRemaining()) {
2943 final int coordType = coord&0xF;
2945 switch (coordType) {
2977 listener.mapScroll(dx, dy);
3013 if (
packet.hasRemaining()) {
3031 if (
packet.hasRemaining()) {
3052 if (
packet.hasRemaining()) {
3084 final int flags0 = flags;
3094 final int startPos =
packet.position();
3099 if (
packet.hasRemaining()) {
3107 }
catch (
final IOException ex) {
3119 final List<String> options =
new ArrayList<>();
3120 while (
packet.hasRemaining()) {
3124 final int startPos =
packet.position();
3129 if (
packet.hasRemaining()) {
3136 if (options.size()%2 != 0) {
3139 for (
int i = 0; i+1 < options.size(); i += 2) {
3140 final String option = options.get(i);
3141 final String value = options.get(i+1);
3144 if (!value.equals(
"1")) {
3145 throw new UnknownCommandException(
"Error: the server is too old for this client since it does not support the spellmon=1 setup option.");
3159 if (!value.equals(
"1")) {
3160 throw new UnknownCommandException(
"Error: the server is too old for this client since it does not support the newmapcmd=1 setup option.");
3165 if (!value.equals(
"1")) {
3166 throw new UnknownCommandException(
"the server is too old for this client since it does not support the facecache=1 setup option.");
3170 case "extendedTextInfos":
3171 if (!value.equals(
"1")) {
3172 throw new UnknownCommandException(
"the server is too old for this client since it does not support the extendedTextInfos=1 setup option.");
3177 if (!value.equals(
"2")) {
3178 throw new UnknownCommandException(
"the server is too old for this client since it does not support the itemcmd=2 setup option.");
3183 final String[] tmp = value.split(
"x", 2);
3184 if (tmp.length != 2) {
3187 final int thisMapWidth;
3188 final int thisMapHeight;
3190 thisMapWidth = Integer.parseInt(tmp[0]);
3191 thisMapHeight = Integer.parseInt(tmp[1]);
3192 }
catch (
final NumberFormatException ignored) {
3196 System.err.println(
"the server sent an unexpected 'setup mapsize "+value+
"'.");
3244 if (!value.equals(
"1")) {
3245 throw new UnknownCommandException(
"the server is too old for this client since it does not support the map2cmd=1 setup option.");
3254 if (!value.equals(
"1")) {
3255 throw new UnknownCommandException(
"the server is too old for this client since it does not support the tick=1 setup option.");
3259 case "num_look_objects":
3271 case "extended_stats":
3276 if (value.equals(
"FALSE")) {
3283 method = Integer.parseInt(value);
3284 }
catch (
final NumberFormatException ignored) {
3287 if (method < 0 || method > 2) {
3293 case "notifications":
3298 System.err.println(
"Warning: ignoring unknown setup option from server: "+option+
"="+value);
3303 if (options.size() != 2 || !options.get(0).equals(
"mapsize") && !options.get(0).equals(
"num_look_objects")) {
3317 final StringBuilder sb =
new StringBuilder();
3318 for (
final String option : options) {
3322 return sb.isEmpty() ?
"" : sb.substring(1);
3334 if (
packet.hasRemaining()) {
3350 final int x =
packet.get();
3351 final int y =
packet.get();
3354 if (
packet.hasRemaining()) {
3370 final int x =
packet.get();
3371 final int y =
packet.get();
3372 final int dir =
packet.get();
3379 if (
packet.hasRemaining()) {
3395 while (
packet.hasRemaining()) {
3522 if (
packet.hasRemaining()) {
3544 final String valName;
3545 final String valNamePl;
3551 int namePlIndex = 0;
3552 while (namePlIndex < nameLength &&
packet.get(
packet.position()+namePlIndex) != 0) {
3556 valNamePl = namePlIndex+1 < nameLength ?
newString(
packet,
packet.position()+namePlIndex+1, nameLength-(namePlIndex+1)) : valName;
3557 ((Buffer)
packet).position(
packet.position()+nameLength);
3562 if (
packet.hasRemaining()) {
3566 debugProtocol.
debugProtocolWrite(
"recv upditem flags="+flags+
" tag="+tag+
" loc="+valLocation+
" flags="+valFlags+
" weight="+valWeight+
" face="+valFaceNum+
" name="+valName+
" name_pl="+valNamePl+
" anim="+valAnim+
" anim_speed="+valAnimSpeed+
" nrof="+valNrof);
3568 fireUpditemReceived(flags, tag, valLocation, valFlags, valWeight, valFaceNum, valName, valNamePl, valAnim, valAnimSpeed, valNrof);
3569 notifyPacketWatcherListeners(
"upditem", () -> flags+
" "+tag+
" "+valLocation+
" "+valFlags+
" "+valWeight+
" "+valFaceNum+
" "+valName+
" "+valNamePl+
" "+valAnim+
" "+valAnimSpeed+
" "+valNrof);
3580 final String step = stepLength > 0 ?
getString(
packet, stepLength) :
"";
3600 if (
packet.hasRemaining()) {
3633 sendSetup(
"want_pickup 1",
"faceset 0",
"sound2 3",
"exp64 1",
"map2cmd 1",
"darkness 1",
"newmapcmd 1",
"facecache 1",
"extendedTextInfos 1",
"itemcmd 2",
"spellmon 1",
"tick 1",
"extended_stats 1",
"loginmethod 2",
"notifications 3");
3636 final int csval0 = csval;
3637 final int scval0 = scval;
3652 final byte[] loginBytes = login.getBytes(
UTF8);
3655 final byte[] passwordBytes = password.getBytes(
UTF8);
3719 public void sendLock(
final boolean val,
final int tag) {
3765 public void sendMove(
final int to,
final int tag,
final int nrof) {
3783 public int sendNcom(
final int repeat, @NotNull
final String command) {
3787 final int thisPacket;
3789 thisPacket =
packet++&0x00FF;
3853 if (options.length <= 0) {
3856 for (String option : options) {
3862 final StringBuilder sb =
new StringBuilder(
"setup");
3863 for (String option : options) {
3864 sb.append(
" ").append(option);
3866 return sb.toString();
3873 if (types.length <= 0) {
3884 for (
int type : types) {
3889 final StringBuilder sb = new StringBuilder(
"toggleextendedtext");
3890 for (int type : types) {
3891 sb.append(
" ").append(type);
3893 return sb.toString();
3899 public void sendVersion(
final int csval,
final int scval, @NotNull
final String vinfo) {
3900 if (debugProtocol !=
null) {
3901 debugProtocol.debugProtocolWrite(
"send version cs="+csval+
" sc="+scval+
" info="+vinfo);
3903 synchronized (writeBuffer) {
3904 ((Buffer)byteBuffer).clear();
3906 byteBuffer.put(VERSION_PREFIX);
3908 byteBuffer.put((
byte)
' ');
3910 byteBuffer.put((
byte)
' ');
3911 byteBuffer.put(vinfo.getBytes(UTF8));
3912 defaultServerConnection.
writePacket(writeBuffer, byteBuffer.position(), () ->
"version "+csval+
" "+scval+
" "+vinfo);
3923 byteBuffer.put((
byte)
'0');
3925 byteBuffer.put(Integer.toString(value).getBytes(StandardCharsets.ISO_8859_1));
3936 final int digit = ch-
'0';
3937 if (digit < 0 || digit > 9) {
3945 final int preferredMapWidth2 = Math.max(1, preferredMapWidth|1);
3946 final int preferredMapHeight2 = Math.max(1, preferredMapHeight|1);
3947 if (this.preferredMapWidth == preferredMapWidth2 && this.preferredMapHeight == preferredMapHeight2) {
3951 this.preferredMapWidth = preferredMapWidth2;
3952 this.preferredMapHeight = preferredMapHeight2;
3954 negotiateMapSize(this.preferredMapWidth, this.preferredMapHeight);
3963 if (this.currentMapWidth == currentMapWidth && this.currentMapHeight == currentMapHeight) {
3967 this.currentMapWidth = currentMapWidth;
3968 this.currentMapHeight = currentMapHeight;
3976 crossfireUpdateMapListener.newMap(currentMapWidth, currentMapHeight);
3991 public void connect(@NotNull
final String hostname,
final int port) {
3996 defaultServerConnection.
connect(hostname, port);
4020 if (debugProtocol !=
null) {
4021 debugProtocol.debugProtocolWrite(
"connection state: "+nextState);
4023 if (clientSocketState != prevState) {
4024 System.err.println(
"Warning: connection state is "+clientSocketState+
" when switching to state "+nextState+
", expecting state "+prevState);
4026 clientSocketState = nextState;
4029 synchronized (writeBuffer) {
4030 param = sendingRequestInfo.isEmpty() ?
"" : sendingRequestInfo.getFirst();
4042 if (debugProtocol !=
null) {
4043 debugProtocol.debugProtocolWrite(
"send accountplay "+name);
4045 synchronized (writeBuffer) {
4046 ((Buffer)byteBuffer).clear();
4048 byteBuffer.put(ACCOUNT_PLAY_PREFIX);
4049 byteBuffer.put(name.getBytes(UTF8));
4050 defaultServerConnection.
writePacket(writeBuffer, byteBuffer.position(), () ->
"accountplay "+name);
4053 final String tmpAccountName = accountName;
4054 if (tmpAccountName !=
null) {
4055 fireSelectCharacter(tmpAccountName, name);
4060 public void sendAccountLink(
final int force, @NotNull
final String login, @NotNull
final String password) {
4062 if (debugProtocol !=
null) {
4063 debugProtocol.debugProtocolWrite(
"send accountaddplayer "+login);
4065 synchronized (writeBuffer) {
4066 ((Buffer)byteBuffer).clear();
4068 byteBuffer.put(ACCOUNT_ADD_PLAYER_PREFIX);
4069 byteBuffer.put((
byte)force);
4070 final byte[] loginBytes = login.getBytes(UTF8);
4071 byteBuffer.put((
byte)loginBytes.length);
4072 byteBuffer.put(loginBytes);
4073 final byte[] passwordBytes = password.getBytes(UTF8);
4074 byteBuffer.put((
byte)passwordBytes.length);
4075 byteBuffer.put(passwordBytes);
4076 defaultServerConnection.
writePacket(writeBuffer, byteBuffer.position(), () ->
"accountaddplayer "+login);
4083 if (debugProtocol !=
null) {
4084 debugProtocol.debugProtocolWrite(
"send accountnew "+login);
4086 accountName = login;
4087 synchronized (writeBuffer) {
4088 ((Buffer)byteBuffer).clear();
4090 byteBuffer.put(ACCOUNT_NEW_PREFIX);
4091 final byte[] loginBytes = login.getBytes(UTF8);
4092 byteBuffer.put((
byte)loginBytes.length);
4093 byteBuffer.put(loginBytes);
4094 final byte[] passwordBytes = password.getBytes(UTF8);
4095 byteBuffer.put((
byte)passwordBytes.length);
4096 byteBuffer.put(passwordBytes);
4097 defaultServerConnection.
writePacket(writeBuffer, byteBuffer.position(), () ->
"accountnew "+login);
4102 public void sendAccountCharacterCreate(@NotNull
final String login, @NotNull
final String password, @NotNull
final Collection<String> attributes) {
4104 if (debugProtocol !=
null) {
4105 debugProtocol.debugProtocolWrite(
"send createplayer "+login+
" "+attributes);
4107 synchronized (writeBuffer) {
4108 ((Buffer)byteBuffer).clear();
4110 byteBuffer.put(CREATE_PLAYER_PREFIX);
4111 final byte[] loginBytes = login.getBytes(UTF8);
4112 byteBuffer.put((
byte)loginBytes.length);
4113 byteBuffer.put(loginBytes);
4114 final byte[] passwordBytes = password.getBytes(UTF8);
4115 byteBuffer.put((
byte)passwordBytes.length);
4116 byteBuffer.put(passwordBytes);
4117 if (loginMethod >= 2) {
4118 for (
final String attribute : attributes) {
4119 final byte[] attributeBytes = attribute.getBytes(UTF8);
4120 byteBuffer.put((
byte)(attributeBytes.length+1));
4121 byteBuffer.put(attributeBytes);
4122 byteBuffer.put((
byte)0);
4125 defaultServerConnection.
writePacket(writeBuffer, byteBuffer.position(), () -> {
4126 final StringBuilder sb =
new StringBuilder(
"createplayer ");
4128 if (loginMethod >= 2) {
4129 for (
final String attribute : attributes) {
4130 sb.append(
" ").append(attribute);
4133 return sb.toString();
4141 if (debugProtocol !=
null) {
4142 debugProtocol.debugProtocolWrite(
"send accountpw");
4144 synchronized (writeBuffer) {
4145 ((Buffer)byteBuffer).clear();
4147 byteBuffer.put(ACCOUNT_PASSWORD_PREFIX);
4148 final byte[] currentPasswordBytes = currentPassword.getBytes(UTF8);
4149 byteBuffer.put((
byte)currentPasswordBytes.length);
4150 byteBuffer.put(currentPasswordBytes);
4151 final byte[] newPasswordBytes = newPassword.getBytes(UTF8);
4152 byteBuffer.put((
byte)newPasswordBytes.length);
4153 byteBuffer.put(newPasswordBytes);
4154 defaultServerConnection.
writePacket(writeBuffer, byteBuffer.position(), () ->
"accountpw");
4164 private static int getInt1(@NotNull
final ByteBuffer byteBuffer) {
4165 return byteBuffer.get()&0xFF;
4174 private static int getInt2(@NotNull
final ByteBuffer byteBuffer) {
4175 return byteBuffer.getShort()&0xFFFF;
4184 private static int getInt4(@NotNull
final ByteBuffer byteBuffer) {
4185 return byteBuffer.getInt();
4194 private static long getInt8(@NotNull
final ByteBuffer byteBuffer) {
4195 return byteBuffer.getLong();
4206 private static String
getString(@NotNull
final ByteBuffer byteBuffer,
final int len) {
4207 final byte[] tmp =
new byte[len];
4208 byteBuffer.get(tmp);
4209 return new String(tmp, UTF8);
4221 final int position = byteBuffer.position();
4222 final int remaining = byteBuffer.remaining();
4224 for (len = 0; len < remaining; len++) {
4225 if (byteBuffer.get(position+len) == delimiter) {
4229 final byte[] tmp =
new byte[len];
4230 byteBuffer.get(tmp);
4231 if (len < remaining) {
4234 return new String(tmp, UTF8);
4243 private static String
hexDump(@NotNull
final ByteBuffer byteBuffer) {
4244 final int len = byteBuffer.limit();
4245 final byte[] data =
new byte[len];
4246 for (
int i = 0; i < len; i++) {
4247 data[i] = byteBuffer.get(i);
4271 crossfireUpdateMapListener.mapClear(x, y);
4275 crossfireUpdateMapListener.mapDarkness(x, y, darkness);
4279 crossfireUpdateMapListener.mapFace(location, face);
4283 crossfireUpdateMapListener.mapAnimation(location, animationNum, animationType);
4287 crossfireUpdateMapListener.mapSmooth(location, smooth);
4291 crossfireUpdateMapListener.mapAnimationSpeed(location, animSpeed);
4294 private void fireMagicMap(
final int x,
final int y,
final byte @NotNull [] @NotNull [] data) {
4295 synchronized (crossfireUpdateMapListener.mapBegin()) {
4296 assert crossfireUpdateMapListener !=
null;
4297 crossfireUpdateMapListener.magicMap(x, y, data);
4298 assert crossfireUpdateMapListener !=
null;
4299 crossfireUpdateMapListener.mapEnd();
4309 synchronized (writeBuffer) {
4310 pendingRequestInfos.add(infoType);
4312 sendPendingRequestInfo();
4320 final String infoType;
4321 synchronized (writeBuffer) {
4322 if (sendingRequestInfo.size() >= CONCURRENT_REQUESTINFO_MESSAGES || pendingRequestInfos.isEmpty()) {
4325 infoType = pendingRequestInfos.remove(0);
4327 sendRequestinfo(infoType);
4336 synchronized (writeBuffer) {
4337 return !sendingRequestInfo.isEmpty() || !pendingRequestInfos.isEmpty();
void setMsg(@NotNull final String msg)
Sets the long description.
void fireDelinvReceived(final int tag)
Interface for classes interested in faces received from the Crossfire server.
void disconnect(@NotNull final String reason)
Disconnects from the server.
ClassRaceInfo finish()
Finishes parsing an entry a returns the ClassRaceInfo for the entry.
static final Charset UTF8
The Charset used for parsing or encoding strings received from or sent to the Crossfire server.
void setCurrentMapSize(final int currentMapWidth, final int currentMapHeight)
Sets the current map size as negotiated with the server.
DefaultCrossfireServerConnection(@NotNull final Model model, @Nullable final DebugWriter debugProtocol, @NotNull final String version)
Creates a new instance.
One possible class or race for character creation.
static final int DEFAULT_MAP_WIDTH
The default map width when no "setup mapsize" command has been sent.
static final int CS_STAT_DEX
The Dexterity Primary stat.
Builder for CharacterInformation instances while parsing an "accountplayers" packet.
static int getInt2(@NotNull final ByteBuffer byteBuffer)
Extracts and removes a 2 byte integer from a ByteBuffer at its current position.
static final byte[] VERSION_PREFIX
The command prefix for the "version" command.
static final int INFO_MAP_DESCRIPTION
Description of a "replyinfo startingmap" entry.
int UPD_FACE
The update flags value for face updates.
void drawInfo(@NotNull final String message, final int color)
Pretends that a drawinfo message has been received.
void processStats(@NotNull final ByteBuffer packet)
Processes a 'stats' server command.
static final int CS_STAT_POW
The Power Primary stat.
static final int CS_STAT_SPELL_ATTUNE
Attuned spell paths of a spell.
static final int CS_STAT_WEAP_SP
The Weapon Speed stat.
void processComc(@NotNull final ByteBuffer packet)
Processes a 'comc' server command.
int packet
The packet id for the next "ncom" command to send.
void processImageInfoReplyinfo(@NotNull final ByteBuffer packet)
Processes a "replyinfo image_info" block.
final Deque< String > sendingRequestInfo
If non-empty: the last sent "requestinfo" commands for which no "replyinfo" response has been receive...
static final Pattern PATTERN_SPACE
Pattern to split a string by spaces.
void start()
Starts operation.
CharacterInformation parseAccountPlayer(@NotNull final ByteBuffer packet, @NotNull final AccountPlayerBuilder accountPlayerBuilder)
Processes one account entry of an 'accountplayers' server command.
static final byte[] TOGGLEEXTENDEDTEXT_PREFIX
The command prefix for the "toggleextendedtext" command.
void connect(@NotNull final String hostname, final int port)
Attempts to connect the client to a server.
void fireDelitemReceived(final int @NotNull[] tags)
void sendAddme()
Sends an "addme" command to the server.
static final byte[] ACCOUNT_PASSWORD_PREFIX
The command prefix for the "accountpw" command.
void cmdMap2CoordinateLayer4(@NotNull final ByteBuffer packet, @NotNull final Location location, final int face)
Processes the additional payload data for a map2 coordinate "layer" sub-command having 4 bytes payloa...
One of the two most important classes, ServerConnection performs most of the network-related work.
static final int CS_STAT_GOLEM_HP
The golem's hitpoints, 0 if no golem.
int COORD_OFFSET
Offset for coordinate values in map2 command.
Implements the map model which is shown in the map and magic map views.
QuestsManager getQuestsManager()
void addKnowledgeType(@NotNull final String type, @NotNull final String name, final int face, final boolean canAttempt)
void addCrossfireMapScrollListener(@NotNull final CrossfireMapScrollListener listener)
Registers a listener to be called whenever the map was scolled.
static int[] getAllTypes(final boolean includeJXClientType)
Returns all defined message types.
void stop()
Stops operation.
void processPlayer(@NotNull final ByteBuffer packet)
Processes a 'player' server command.
void processNewMap(@NotNull final ByteBuffer packet)
Processes a 'newmap' server command.
void cmdMap2CoordinateDarkness(@NotNull final ByteBuffer packet, final int x, final int y, final int len)
Processes the payload data for a map2 coordinate "darkness" sub-command.
void removeClientSocketListener(@NotNull final ClientSocketListener clientSocketListener)
Removes a ClientSocketListener to notify.
void processQuery(@NotNull final ByteBuffer packet)
Processes a 'query' server command.
static final byte[] ACCOUNT_PLAY_PREFIX
The command prefix for the "accountplay" command.
static void parseNewCharInfoValue(@NotNull final NewCharInfoBuilder newCharInfoBuilder, final boolean required, @NotNull final String variableName, @NotNull final String values)
Parses an 'R' or 'O' entry of a "replyinfo newcharinfo" packet.
final List< String > pendingRequestInfos
Pending "requestinfo" commands that will be sent as soon sendingRequestInfo is not full.
static final int CS_STAT_APPLIED_CON
The constitution primary stat changes due to gear or skills.
void sendAccountLink(final int force, @NotNull final String login, @NotNull final String password)
Sends a request to add an existing character to an account.
static final byte[] ASKFACE_PREFIX
The command prefix for the "askface" command.
static final byte[] ADDME_PREFIX
The command prefix for the "addme" command.
int COORD_LAYER8
Face information for layer 8.
void mapEnd()
Parsing of "map2" has been finished.
final byte[] writeBuffer
Buffer to build commands to send.
static final byte[] CREATE_PLAYER_PREFIX
The command prefix for the "createplayer" command.
int pendingMapHeight
The map height that is being negotiated with the server.
static String hexDump(final byte @NotNull[] data, final int start, final int end)
Returns a hex dump of a part of a byte array.
static void parseClassRaceInfoStats(@NotNull final ByteBuffer packet, @NotNull final ClassRaceInfoBuilder rb)
Parses a "stats" entry of a "replyinfo race_info" or "replyinfo class_info" packet.
static final int CS_STAT_OVERLOAD
Indicates how much the character is overloaded: 0=not overloaded, 1=overloaded.
Utility class for converting stat values to stat names.
static final int CS_STAT_APPLIED_INT
The integer primary stat changes due to gear or skills.
static final int RESIST_TYPES
The total number of resistances.
int UPD_ANIMSPEED
The update flags value for animation speed updates.
static final int CS_STAT_WIS
The Wisdom Primary stat.
void setStatInt2(final int stat, final short param)
Updates a stat value with a two-byte int value.
boolean hasPendingReplyinfo()
Returns whether at least one replyinfo message is pending.
void setSkillExtra(final int id, @NotNull final String message)
Defines additional skill information, when the server supports it.
static final int CS_STAT_TITLE
The Title stat.
static final int CS_STAT_DAM
The Damage stat.
int COORD_CLEAR_SPACE
Clear a square.
void processReplyInfo(@NotNull final ByteBuffer packet)
Processes a 'replyinfo' server command.
int UPD_NAME
The update flags value for name updates.
int COORD_LAYER5
Face information for layer 5.
void setStatSkill(final int stat, final int level, final long experience)
Updates a stat value with a skill value.
static final int CS_STAT_SPELL_DENY
Denied spell paths of a spell.
General information for creating new characters.
static final int CS_STAT_FOOD
The Food stat.
void waitForCurrentNumLookObjectsValid()
Waits until getCurrentNumLookObjects() is stable.
static final int CS_STAT_APPLIED_STR
The strength primary stat changes due to gear or skills.
void clearFailure()
Inform the various failure listeners that they can clean the last displayed failure.
int preferredMapWidth
The map width in tiles that is negotiated with the server.
static final int ACL_LEVEL
Parameter type in the "accountplayers" command.
void processPickup(@NotNull final ByteBuffer packet)
Processes a 'pickup' server command.
static final int CS_STAT_RACE_CHA
The race's maximum charisma primary stat.
static final byte[] ACCOUNT_ADD_PLAYER_PREFIX
The command prefix for the "accountaddplayer" command.
static final int CS_NUM_SKILLS
CS_NUM_SKILLS does not match how many skills there really are - instead, it is used as a range of val...
int preferredMapHeight
The map height in tiles that is negotiated with the server.
static final int INFO_MAP_ARCH_NAME
Archetype name of a "replyinfo startingmap" entry.
void fireUpditemReceived(final int flags, final int tag, final int valLocation, final int valFlags, final int valWeight, final int valFaceNum, @NotNull final String valName, @NotNull final String valNamePl, final int valAnim, final int valAnimSpeed, final int valNrof)
static final int UPD_SP_MANA
Flag for updspell command: mana is present.
void processSetupNumLookObjects(@NotNull final String value)
Called when a "setup num_look_objects" response has been received from the server.
Interface defining constants for the "upditem" Crossfire protocol message.
void addKnowledge(final int index, @NotNull final String type, @NotNull final String title, final int face)
void processPacket(@NotNull final ByteBuffer packet)
Processes a received packet.
static final int CS_STAT_SKILLINFO
CS_STAT_SKILLINFO is used as the starting index point.
void sendAccountPlay(@NotNull final String name)
Sends a request to play a character from an account.
int currentMapWidth
The currently active map width.
void writePacket(final byte @NotNull[] packet, final int length, @NotNull final ClientSocketMonitorCommand monitor)
Writes a Crossfire Message on the socket, so it is sent to the server.
Encapsulates the message type numbers for drawextinfo messages.
CONNECTING
The socket is being established.
Manages image information ("faces") needed to display the map view, items, and spell icons.
Abstract base class for CrossfireServerConnection implementing classes.
int currentMapHeight
The currently active map height.
static String getString(@NotNull final ByteBuffer byteBuffer, final int len)
Extracts and removes a string from a ByteBuffer at its current position.
void processUpdItem(@NotNull final ByteBuffer packet)
Processes an 'upditem' server command.
static final int CS_STAT_RACE_CON
The race's maximum constitution primary stat.
void setPreferredMapSize(final int preferredMapWidth, final int preferredMapHeight)
Sets the preferred map size.
void processClassListReplyinfo(@NotNull final ByteBuffer packet)
Processes a "replyinfo class_list" block.
void processUpdQuest(@NotNull final ByteBuffer packet)
Processes an 'updquest' server command.
static final int CS_STAT_BASE_POW
The power primary stat without boosts or depletions.
static final int CS_STAT_RACE_WIS
The race's maximum wisdom primary stat.
static final int CS_STAT_STR
The Strength Primary stat.
static String getStringDelimiter(@NotNull final ByteBuffer byteBuffer, final char delimiter)
Extracts and removes a string from a ByteBuffer at its current position.
void processStartingMapReplyinfo(@NotNull final ByteBuffer packet)
Processes a "replyinfo startingmap" block.
ACCOUNT_INFO
The client is connected, and account information is being exchanged.
void processSkillExtraReplyinfo(@NotNull final ByteBuffer packet)
Processes a "replyinfo skill_extra" block.
int getCurrentNumLookObjects()
Returns the currently negotiated setup value of "num_look_objects".
int ANIM_MASK
The mask for extracting the animation ID.
void stop()
Stops operation.
static final int CS_STAT_BASE_INT
The integer primary stat without boosts or depletions.
static final int CS_STAT_RANGE
The Range stat - this is what is currently readied by the player to fire.
void disconnect(@NotNull final String reason)
Disconnects from the server.
A list of event listeners.
final EventListenerList2< AskfaceFaceQueueListener > askfaceFaceQueueListeners
The AskfaceQueueListeners to notify.
static final int CS_STAT_AC
The Armor Class stat.
Manages all known spells.
static final int UPD_SP_DAMAGE
Flag for updspell command: damage is present.
void processMagicMap(@NotNull final ByteBuffer packet)
Processes a 'magicmap' server command.
void cmdMap2CoordinateClearSpace(final int x, final int y, final int len)
Processes the payload data for a map2 coordinate "clear_space" sub-command.
void connect(@NotNull final String hostname, final int port)
Attempts to connect the client to a server.
static int parseDigit(final byte ch)
Parses a character into an integer.
void processMapExtended(@NotNull final ByteBuffer packet)
Processes a 'mapextended' server command.
static final int ACL_CLASS
Parameter type in the "accountplayers" command.
void fireMapDarkness(final int x, final int y, final int darkness)
NewCharInfo finish()
Finished parsing and returns the NewCharInfo instance for the parsed entry.
static final int CS_STAT_RESIST_START
Beginning index of the resistances.
static final int CS_STAT_HP
The Hit Points stat.
static final byte[] SETUP_PREFIX
The command prefix for the "setup" command.
static final byte[] ACCOUNT_LOGIN_PREFIX
The command prefix for the "accountlogin" command.
static final byte[] APPLY_PREFIX
The command prefix for the "apply" command.
String accountName
The account name.
static final Pattern PATTERN_DOT
Pattern to split a string by ":".
void setSimpleWeaponSpeed(final boolean simpleWeaponSpeed)
Sets whether the CS_STAT_WEAP_SP value contains the weapon speed directly.
void setDescription(@NotNull final String description)
Sets the description of the current entry.
static final int ACL_FACE
Parameter type in the "accountplayers" command.
static String getStatNames(final int stat)
Returns the stat name for a stat value.
void fireMapAnimation(@NotNull final Location location, final int animationNum, final int animationType)
void debugProtocolWrite(@NotNull final CharSequence str)
Writes a message to the debug protocol.
NewCharacterInformation getNewCharacterInformation()
Returns the NewCharacterInformation for creating new characters.
void processImage2(@NotNull final ByteBuffer packet)
Processes an 'image2' server command.
void addFaceReceivedListener(@NotNull final AskfaceFaceQueueListener listener)
Registers a listener to be called whenever a face has been received.
static final int CS_STAT_MAXHP
The Maximum Hit Points stat.
static final byte[] ACCOUNT_NEW_PREFIX
The command prefix for the "accountnew" command.
int COORD_LAYER0
Face information for layer 0.
static final int CS_STAT_GOD_NAME
The character's god or NO_GOD_NAME if he has none.
void setName(@NotNull final String name)
Sets the human-readable stat name.
void addSpell(final int tag, final int level, final int castingTime, final int mana, final int grace, final int damage, final int skill, final int path, final int faceNum, @NotNull final String spellName, @NotNull final String message)
Adds a new spell.
A choice for character creation.
final EventListenerList2< CrossfireMapScrollListener > crossfireMapScrollListeners
The CrossfireMapScrollListeners to notify.
KnowledgeManager getKnowledgeManager()
void setClientSocketState(@NotNull final ClientSocketState clientSocketState)
Called whenever the client socket state has changed.
void cmdReplyinfo(@NotNull final String infoType, final ByteBuffer packet)
Handles the replyinfo server to client command.
void sendExamine(final int tag)
Sends an "examine" command to the server.
void processDelSpell(@NotNull final ByteBuffer packet)
Processes a 'delspell' server command.
Utility class for en-/decoding hexadecimal strings.
void processAddmeSuccess()
Processes an 'addme_success' server command.
void processDelInv(@NotNull final ByteBuffer packet)
Processes a 'delinv' server command.
void updateSpell(final int flags, final int tag, final int mana, final int grace, final int damage)
Updates spell information.
void fireMapSmooth(@NotNull final Location location, final int smooth)
void setClientSocketState(@NotNull final ClientSocketState clientSocketState, @NotNull final String param)
Sets the new ClientSocketState.
static final int CS_STAT_APPLIED_CHA
The charisma primary stat changes due to gear or skills.
static final int CS_STAT_EXP64
The Global Experience (64bit encoding) stat.
void sendLookat(final int dx, final int dy)
Sends a "lookat" command to the server.
int TYPE_SCROLL
Scroll information.
void cmdMap2CoordinateLayer(@NotNull final ByteBuffer packet, final int x, final int y, final int len, final int layer)
Processes the payload data for a map2 coordinate "layer" sub-command.
static final int ACL_PARTY
Parameter type in the "accountplayers" command.
static final int CS_STAT_ITEM_POWER
The maximum item power the character can handle.
void processDelItem(@NotNull final ByteBuffer packet)
Processes a 'delitem' server command.
static final int CS_STAT_SP
The Spell Points stat.
static final int CS_STAT_SPELL_REPEL
Repelled spell paths of a spell.
final Model model
The Model instance that is updated.
void fireCommandQueryReceived(@NotNull final String prompt, final int queryType)
void fireCommandComcReceived(final int packetNo, final int time)
void sendAccountCreate(@NotNull final String login, @NotNull final String password)
Sends a request to create a new account.
static final int CS_STAT_LEVEL
The Global Level stat.
int ANIM_TYPE_SHIFT
The lowest bit of the animation type.
void sendQueuedRequestinfo(@NotNull final String infoType)
Sends a "requestinfo" packet asynchronously.
void processUpdSpell(@NotNull final ByteBuffer packet)
Processes an 'updspell' server command.
int COORD_LAYER3
Face information for layer 3.
void addQuest(final int code, @NotNull final String title, final int face, final boolean replay, final int parent, final boolean end, @NotNull final String description)
Adds a new quest.
int loginMethod
The login method version supported by the server we're connected to.
void cmdMap2CoordinateLayer3(@NotNull final ByteBuffer packet, @NotNull final Location location, final int face)
Processes the additional payload data for a map2 coordinate "layer" sub-command having 4 bytes payloa...
void putDecimal(final int value)
Appends an integer in decimal ASCII representation to byteBuffer.
int UPD_FLAGS
The update flags value for flags updates.
CrossfireUpdateMapListener crossfireUpdateMapListener
The CrossfireUpdateMapListener to be notified.
void processSmooth(@NotNull final ByteBuffer packet)
Processes a 'smooth' server command.
static final int CS_STAT_RACE_INT
The race's maximum intelligence primary stat.
static void parseNewCharInfoValues(@NotNull final NewCharInfoBuilder newCharInfoBuilder, @NotNull final String variableName, @NotNull final String values)
Parses a 'V' entry of a "replyinfo newcharinfo" packet.
static final int CS_STAT_RACE_STR
The race's maximum strength primary stat.
static final int CS_STAT_RACE_DEX
The race's maximum dexterity primary stat.
void fireTick(final int tickNo)
static final int ACL_RACE
Parameter type in the "accountplayers" command.
void processSound(@NotNull final ByteBuffer packet)
Processes a 'sound' server command.
void addClientSocketListener(@NotNull final ClientSocketListener clientSocketListener)
Adds a ClientSocketListener to notify.
final ByteBuffer byteBuffer
A byte buffer using writeBuffer to store the data.
void start()
Starts operation.
Builder for ClassRaceInfo instances while parsing a "replyinfo race_info" packet.
static final int CS_STAT_CHA
The Charisma Primary stat.
void setPreferredNumLookObjects(final int preferredNumLookObjects)
Sets the maximum number of objects in the ground view.
int UPD_LOCATION
The update flags value for location updates.
void setExpTable(final long @NotNull[] expTable)
Updates the experience table information.
final ClientSocketListener clientSocketListener
The ClientSocketListener attached to the server socket.
int COORD_LAYER6
Face information for layer 6.
String getAccountName()
Returns the current account name.
void sendReply(@NotNull final String text)
Sends a "reply" command to the server.
void setPreferredNumLookObjects(final int preferredNumLookObjects)
Sets the preferred number of ground items.
void fireMapAnimationSpeed(@NotNull final Location location, final int animSpeed)
void deleteSpell(final int tag)
Deletes a spell.
static final int CS_STAT_WEIGHT_LIM
The Weight Limit stat.
void fireNewMap()
Notifies all listeners that a "newmap" command has been received.
void clearSkills()
Clears all skills.
void processSkillInfoReplyinfo(@NotNull final ByteBuffer packet)
Processes a "replyinfo skill_info" block.
void fireCommandSoundReceived(final int x, final int y, final int num, final int type)
static final byte[] LOCK_PREFIX
The command prefix for the "lock" command.
static final int CS_STAT_GOLEM_MAXHP
The golem's maximum hitpoints, 0 if no golem.
void processFailure(@NotNull final ByteBuffer packet)
Processes a 'failure' server command.
Interface defining constants for the "map2" Crossfire protocol message.
static final byte[] MOVE_PREFIX
The command prefix for the "move" command.
static final int INFO_MAP_NAME
Proper name of a "replyinfo startingmap" entry.
void fireFailure(@NotNull final String command, @NotNull final String arguments)
static final int CS_STAT_WC
The Weapon Class stat.
static void parseClassRaceInfoChoice(@NotNull final ByteBuffer packet, @NotNull final ClassRaceInfoBuilder rb)
Parses a "choice" entry of a "replyinfo race_info" or "replyinfo class_info" packet.
This is the representation of all the statistics of a player, like its speed or its experience.
int TYPE_COORDINATE
Normal coordinate.
static final int DEFAULT_MAP_HEIGHT
The default map height when no "setup mapsize" command has been sent.
static final int CS_STAT_MAXGRACE
The Maximum Grace stat.
int COORD_LAYER7
Face information for layer 7.
void fireStartAccountList(@NotNull final String accountName)
void processMusic(@NotNull final ByteBuffer packet)
Processes a 'music' server command.
void updateSmoothFace(final int face, final int smoothFace)
Updates smooth face information.
final NumLookObjects numLookObjects
The NumLookObjects instance for negotiating the size of the ground view.
void mapScroll(int dx, int dy)
Part of "map2" parsing: scroll the map view.
void fireMapClear(final int x, final int y)
Default implementation of CrossfireServerConnection.
void fireReplySent()
Notifies all listeners about a "reply" command that has been sent to the Crossfire server.
static final int CS_STAT_CON
The Constitution Primary stat.
void processFace2(@NotNull final ByteBuffer packet)
Processes a 'face2' server command.
void connected()
Called after the server connection has been established.
static String newString(@NotNull final ByteBuffer byteBuffer, final int start, final int len)
Extracts a string from a ByteBuffer range.
void fireCommandSound2Received(final int x, final int y, final int dir, final int volume, final int type, @NotNull final String action, @NotNull final String name)
final String version
The version information to send when connecting to the server.
void sendMark(final int tag)
Sends a "mark" command to the server.
void sendMove(final int to, final int tag, final int nrof)
Sends a "move" command to the server.
void addClientSocketListener(@NotNull final ClientSocketListener clientSocketListener)
Adds a ClientSocketListener to notify.
static final int CS_STAT_BASE_CON
The constitution primary stat without boosts or depletions.
void setStatString(final int stat, @NotNull final String param)
Updates a stat value with a string value.
static final int CS_STAT_APPLIED_DEX
The dexterity primary stat changes due to gear or skills.
void sendVersion(final int csval, final int scval, @NotNull final String vinfo)
Sends a "version" command to the server.
void sendRequestinfo(@NotNull final String infoType)
Sends a "requestinfo" command to the server.
int COORD_LAYER1
Face information for layer 1.
static final byte[] REQUESTINFO_PREFIX
The command prefix for the "requestinfo" command.
SmoothFaces getSmoothFaces()
void processAddKnowledge(@NotNull final ByteBuffer packet)
Processes an "addknowledge" block.
void drawextinfo(final int color, final int type, final int subtype, @NotNull final String message)
Interface for listeners interested in map related commands.
void sendApply(final int tag)
Sends an "apply" command to the server.
final DefaultServerConnection defaultServerConnection
The physical server connection.
void processKnowledgeInfoReplyinfo(@NotNull final ByteBuffer packet)
Processes a "replyinfo knowledge_info" block.
ExperienceTable getExperienceTable()
static final int CS_STAT_BASE_STR
The strength primary stat without boosts or depletions.
static int getInt1(@NotNull final ByteBuffer byteBuffer)
Extracts and removes a 1 byte integer from a ByteBuffer at its current position.
int UPD_NROF
The update flags value for nrof updates.
GuiStateManager getGuiStateManager()
static final byte[] LOOKAT_PREFIX
The command prefix for the "lookat" command.
void addAnimation(final int animationId, final int @NotNull[] faces)
Defines a new animation.
void notifyPacketWatcherListeners(@NotNull final String command, @NotNull final ClientSocketMonitorCommand args)
Notifies all ReceivedPacketListeners about a packet.
int COORD_LAYER2
Face information for layer 2.
ADDME
"addme" protocol commands are being exchanged.
void sendAskface(final int faceNum)
Sends an "askface" command.
void sendToggleextendedtext(@NotNull final int... types)
Sends a "toggleextendedtext" command to the server.
static final int ACL_MAP
Parameter type in the "accountplayers" command.
Builder for NewCharInfo instances while parsing a "replyinfo newcharinfo" response packet.
void sendAccountCharacterCreate(@NotNull final String login, @NotNull final String password, @NotNull final Collection< String > attributes)
Sends a request to create a new character associated to the account.
static final int CS_STAT_INT
The Intelligence Primary stat.
void sendAccountLogin(@NotNull final String login, @NotNull final String password)
Asks for an account login.
boolean newmap
Whether a "newmap" command has been received but no "map2" command yet.
Interface for listeners interested in ClientSocket related events.
void setCrossfireUpdateMapListener(@NotNull final CrossfireUpdateMapListener listener)
Sets a listener to be notified about map changes.
static final String[] EMPTY_STRING_ARRAY
An empty array of Strings.
Animations getAnimations()
Returns the Animations instance.
Collection< StartingMap > finish()
Finishes parsing.
static final byte[] EXAMINE_PREFIX
The command prefix for the "examine" command.
void sendLock(final boolean val, final int tag)
Sends a "lock" command to the server.
void fireAddAccount(@NotNull final CharacterInformation characterInformation)
void processSound2(@NotNull final ByteBuffer packet)
Processes a 'sound2' server command.
int COORD_LAYER4
Face information for layer 4.
void processAddSpell(@NotNull final ByteBuffer packet)
Processes an 'addspell' server command.
static final int CS_STAT_FLAGS
The various flags used in stats.
static final int UPD_SP_GRACE
Flag for updspell command: grace is present.
void cmdMap2Coordinate(@NotNull final ByteBuffer packet, final int x, final int y)
Processes the payload data for a map2 coordinate command.
REQUESTINFO
"requestinfo" protocol commands are being exchanged.
Builder for StartingMap instances while parsing a "replyinfo startingmap" response packet.
void fireMusicReceived(@NotNull final String music)
void processRaceListReplyinfo(@NotNull final ByteBuffer packet)
Processes a "replyinfo race_list" block.
void processClassRaceInfoReplyinfo(@NotNull final ByteBuffer packet, final boolean raceInfo)
Processes a "replyinfo race_info" or "replyinfo class_info" block.
int UPD_ANIM
The update flags value for animation updates.
void fireMapFace(@NotNull final Location location, final int face)
static String hexDump(@NotNull final ByteBuffer byteBuffer)
Returns a hex-dump of a ByteBuffer.
VERSION
"version" protocol commands are being exchanged.
int getCurrentNumLookObjects()
Returns the current number of ground items.
void setName(@NotNull final String name)
Sets the name of the current entry.
An UnknownCommandException is generated whenever an unknown message packet is received from the serve...
void processTick(@NotNull final ByteBuffer packet)
Processes a 'tick' server command.
static final int CONCURRENT_REQUESTINFO_MESSAGES
The number of requestinfo messages to send before waiting for replyinfo messages.
void updateQuest(final int code, final boolean end, @NotNull final String step)
Updates quest information.
Interface for querying monitor commands for script processes.
void firePlayerReceived(final int tag, final int weight, final int faceNum, @NotNull final String name)
void fireFaceReceived(final int faceNum, final int faceSetNum, final int faceChecksum, @NotNull final String faceName)
void fireEndAccountList(final int count)
static final int ACL_NAME
Parameter type in the "accountplayers" command.
void fireMarkSent(final int tag)
Notifies all listeners about a "mark" command that has been sent to the Crossfire server.
void processVersion(@NotNull final ByteBuffer packet)
Processes a 'version' server command.
static final int CS_STAT_APPLIED_POW
The power primary stat changes due to gear or skills.
void processNewCharInfoReplyinfo(@NotNull final ByteBuffer packet)
Processes a "replyinfo newcharinfo" block.
void setStatInt4(final int stat, final int param)
Updates a stat value with a four-byte int value.
void sendSetup(@NotNull final String... options)
Sends a "setup" command to the server.
Writer debug information to a log file.
void waitForCurrentNumLookObjectsValid()
Waits until getCurrentNumLookObjects() is stable.
int FACE_ANIMATION
The bit value whether this is a face or an animation.
static final int CS_STAT_RACE_POW
The race's maximum power primary stat.
static final int CS_STAT_SPEED
The Speed stat.
int sendNcom(final int repeat, @NotNull final String command)
Sends a "ncom" command to the server.
void processItem2(@NotNull final ByteBuffer packet)
Processes an 'item2' server command.
void processAddQuest(@NotNull final ByteBuffer packet)
Processes an 'addquest' server command.
ClientSocketState clientSocketState
The current connection state.
int COORD_DARKNESS
Darkness information.
static final int ACL_FACE_NUM
Parameter type in the "accountplayers" command.
SETUP
"setup" protocol commands are being exchanged.
void processGoodbye(@NotNull final ByteBuffer packet)
Processes a 'goodbye' server command.
static final Pattern PATTERN_BAR
Pattern to split a string by "|".
void processExtendedInfoSet(@NotNull final ByteBuffer packet)
Processes an 'ExtendedInfoSet' server command.
void setArchName(@NotNull final String archName)
Starts a new starting map entry.
Connection progress states of the Crossfire server connection.
static final int CS_STAT_GRACE
The Grace stat.
void negotiateMapSize(final int mapWidth, final int mapHeight)
Requests a change of the map size from the server.
static final int CS_STAT_MAXSP
The Maximum Spell Points stat.
static final int CS_STAT_APPLIED_WIS
The wisdom primary stat changes due to gear or skills.
static final int CS_STAT_ARMOUR
The Armour stat.
static final int CS_STAT_CHARACTER_FLAGS
Flags the character's current state.
static final byte[] NCOM_PREFIX
The command prefix for the "ncom" command.
int UPD_WEIGHT
The update flags value for weight updates.
static final int CS_STAT_BASE_DEX
The dexterity primary stat without boosts or depletions.
final DebugWriter debugProtocol
The appender to write protocol commands to.
void processAddmeFailed()
Processes an 'addme_failed' server command.
void processExtendedTextSet(@NotNull final ByteBuffer packet)
Processes an 'ExtendedTextSet' server command.
void processSetup(@NotNull final ByteBuffer packet)
Processes a 'setup' server command.
static long getInt8(@NotNull final ByteBuffer byteBuffer)
Extracts and removes an 8 byte integer from a ByteBuffer at its current position.
void processAccountPlayers(@NotNull final ByteBuffer packet)
Processes an 'accountplayers' server command.
void processDrawInfo(@NotNull final ByteBuffer packet)
Processes a 'drawinfo' server command.
int pendingMapWidth
The map width that is being negotiated with the server.
void fireAddItemReceived(final int location, final int tag, final int flags, final int weight, final int faceNum, final String name, final String namePl, final int anim, final int animSpeed, final int nrof, final int type)
SpellsManager getSpellsManager()
boolean connected
Whether the current client socket state is ClientSocketState#CONNECTED.
static void parseNewCharInfoInformational(@NotNull final String variableName, @NotNull final String values)
Parses an 'I' entry of a "replyinfo newcharinfo" packet.
void sendPendingRequestInfo()
Sends the next asynchronous "requestinfo" packet if possible.
void addSkill(final int id, @NotNull final String skillName, final int face)
Adds a new skill to the list of known skills.
void fireMagicMap(final int x, final int y, final byte @NotNull[] @NotNull[] data)
void setStatInt8(final int stat, final long param)
Updates a stat value with an eight-byte int value.
void setClientSocketState(@NotNull final ClientSocketState prevState, @NotNull final ClientSocketState nextState)
Updates the clientSocketState.
static final int CS_STAT_EXP
The Global Experience (32bit encoding) stat.
void firePickupChanged(final int pickupOptions)
int ANIM_TYPE_MASK
The mask for extracting the animation type.
static final int CS_STAT_BASE_CHA
The charisma primary stat without boosts or depletions.
static final int CS_STAT_BASE_WIS
The wisdom primary stat without boosts or depletions.
CONNECT_FAILED
A connection could not be established.
void removeClientSocketListener(@NotNull final ClientSocketListener clientSocketListener)
Removes a ClientSocketListener to notify.
void processAnim(@NotNull final ByteBuffer packet)
Processes an 'anim' server command.
void sendRawString(@NotNull final String command)
Sends an arbitrary string command to the server.
void processMap2(@NotNull final ByteBuffer packet)
Processes a 'map2' server command.
static final byte[] MARK_PREFIX
The command prefix for the "mark" command.
Combines all model classes that are updated.
Negotiates the size of the ground view in items with the Crossfire server.
CONNECTED
Connection is fully established.
static final byte[] REPLY_PREFIX
The command prefix for the "reply" command.
int COORD_LAYER9
Face information for layer 9.
static int getInt4(@NotNull final ByteBuffer byteBuffer)
Extracts and removes a 4 byte integer from a ByteBuffer at its current position.
void processExpTableReplyinfo(@NotNull final ByteBuffer packet)
Processes a "replyinfo exp_table" block.
void sendAccountPassword(@NotNull final String currentPassword, @NotNull final String newPassword)
Sends a request to change the account's password.
Object mapBegin()
Parsing of a "map2" command has been started.
void processDrawExtInfo(@NotNull final ByteBuffer packet)
Processes a 'drawextinfo' server command.