Crossfire JXClient, Trunk  R20561
PacketWatcher.java
Go to the documentation of this file.
1 /*
2  * This file is part of JXClient, the Fullscreen Java Crossfire Client.
3  *
4  * JXClient is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * JXClient is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with JXClient; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  * Copyright (C) 2005-2008 Yann Chachkoff.
19  * Copyright (C) 2006-2011 Andreas Kirschbaum.
20  */
21 
22 package com.realtime.crossfire.jxclient.scripts;
23 
26 import java.nio.ByteBuffer;
27 import java.util.Collection;
28 import java.util.HashSet;
29 import java.util.regex.Pattern;
30 import org.jetbrains.annotations.NotNull;
31 import org.jetbrains.annotations.Nullable;
32 
37 public class PacketWatcher {
38 
42  @NotNull
43  private final Collection<String> commands = new HashSet<>();
44 
48  @NotNull
50 
54  @NotNull
56 
61  @Nullable
62  private Pattern pattern;
63 
69  @NotNull
71 
72  @Override
73  public void processEmpty(@NotNull final String command) {
74  if (matchesCommand(command)) {
75  scriptProcess.commandSent("watch "+command);
76  }
77  }
78 
79  @Override
80  public void processAscii(@NotNull final String command, @NotNull final ByteBuffer packet) {
81  if (matchesCommand(command)) {
82  final byte[] data = new byte[packet.remaining()];
83  packet.get(data);
84  scriptProcess.commandSent("watch "+command+" "+new String(data)); // XXX: uses default encoding
85  }
86  }
87 
88  @Override
89  public void processShortArray(@NotNull final String command, @NotNull final ByteBuffer packet) {
90  if (matchesCommand(command)) {
91  final StringBuilder sb = new StringBuilder("watch ");
92  sb.append(command);
93  for (int i = 0; i < 100 && packet.remaining() >= 2; i++) {
94  sb.append(' ');
95  sb.append(getShort(packet));
96  }
97  scriptProcess.commandSent(sb.toString());
98  }
99  }
100 
101  @Override
102  public void processIntArray(@NotNull final String command, @NotNull final ByteBuffer packet) {
103  if (matchesCommand(command)) {
104  final StringBuilder sb = new StringBuilder("watch ");
105  sb.append(command);
106  while (packet.remaining() >= 4) {
107  sb.append(' ');
108  sb.append(getInt(packet));
109  }
110  scriptProcess.commandSent(sb.toString());
111  }
112  }
113 
114  @Override
115  public void processShortInt(@NotNull final String command, @NotNull final ByteBuffer packet) {
116  if (packet.remaining() == 6 && matchesCommand(command)) {
117  scriptProcess.commandSent("watch "+command+" "+getShort(packet)+" "+getInt(packet));
118  }
119  }
120 
121  @Override
122  public void processMixed(@NotNull final String command, @NotNull final ByteBuffer packet) {
123  if (matchesCommand(command)) {
124  //noinspection StringBufferReplaceableByString
125  final StringBuilder sb = new StringBuilder("watch ");
126  sb.append(command);
127  sb.append(' ');
128  sb.append(packet.remaining());
129  scriptProcess.commandSent(sb.toString());
130  }
131  }
132 
133  @Override
134  public void processStats(@NotNull final String command, final int stat, @NotNull final Object[] args) {
135  if (matchesCommand(command)) {
136  final StringBuilder sb = new StringBuilder("watch ");
137  sb.append(command);
138  sb.append(' ');
139  sb.append(StatUtils.getStatNames(stat));
140  for (final Object arg : args) {
141  sb.append(' ');
142  sb.append(arg);
143  }
144  scriptProcess.commandSent(sb.toString());
145  }
146  }
147 
148  @Override
149  public void processNoData(@NotNull final String command, @NotNull final ByteBuffer packet) {
150  processMixed(command, packet);
151  }
152 
158  private int getShort(@NotNull final ByteBuffer packet) {
159  return packet.getShort()&0xFFFF;
160  }
161 
167  private int getInt(@NotNull final ByteBuffer packet) {
168  return packet.getInt();
169  }
170 
171  };
172 
178  public PacketWatcher(@NotNull final CrossfireServerConnection crossfireServerConnection, @NotNull final ScriptProcess scriptProcess) {
179  this.crossfireServerConnection = crossfireServerConnection;
180  this.scriptProcess = scriptProcess;
181  rebuildPattern();
182  }
183 
188  public void destroy() {
189  if (pattern != null) {
190  pattern = null;
191  crossfireServerConnection.removePacketWatcherListener(receivedPacketListener);
192  }
193  }
194 
198  private void rebuildPattern() {
199  final StringBuilder sb = new StringBuilder();
200  for (final String command : commands) {
201  sb.append(Pattern.quote(command));
202  sb.append(".*|");
203  }
204  final int length = sb.length();
205  if (length <= 0) {
206  if (pattern != null) {
207  pattern = null;
208  crossfireServerConnection.removePacketWatcherListener(receivedPacketListener);
209  }
210  } else {
211  if (pattern == null) {
212  crossfireServerConnection.addPacketWatcherListener(receivedPacketListener);
213  }
214  sb.setLength(length-1);
215  pattern = Pattern.compile(sb.toString());
216  }
217  }
218 
223  public void addCommand(@NotNull final String command) {
224  if (commands.add(command)) {
225  rebuildPattern();
226  }
227  }
228 
233  public void removeCommand(@NotNull final String command) {
234  if (commands.remove(command)) {
235  rebuildPattern();
236  }
237  }
238 
244  private boolean matchesCommand(@NotNull final CharSequence command) {
245  return pattern != null && pattern.matcher(command).matches();
246  }
247 
248 }
void destroy()
Releases allocated resources.
boolean matchesCommand(@NotNull final CharSequence command)
Returns whether a command matches the currently watched commands.
void removePacketWatcherListener(@NotNull ReceivedPacketListener listener)
Removes a listener to be notified about received packets.
void rebuildPattern()
Rebuilds pattern from commands.
void addCommand(@NotNull final String command)
Adds a command to watch for.
static String getStatNames(final int stat)
Returns the stat name for a stat value.
Definition: StatUtils.java:115
final CrossfireServerConnection crossfireServerConnection
The CrossfireServerConnection to watch.
final Collection< String > commands
The commands to watch for.
final ReceivedPacketListener receivedPacketListener
The ReceivedPacketListener attached to crossfireServerConnection.
Utility class for converting stat values to stat names.
Definition: StatUtils.java:33
void removeCommand(@NotNull final String command)
Removes a command to watch for.
PacketWatcher(@NotNull final CrossfireServerConnection crossfireServerConnection, @NotNull final ScriptProcess scriptProcess)
Creates a new instance.
Interface for listeners interested in received packets.
Implements the "watch" function for client-sided scripts.
void addPacketWatcherListener(@NotNull ReceivedPacketListener listener)
Adds a listener to be notified about received packets.
void commandSent(@NotNull String cmd)
Sends a message to the script process.
Pattern pattern
A Pattern matching all commands.
An external command executed as a client-sided script.
Adds encoding/decoding of crossfire protocol packets to a ServerConnection.
final ScriptProcess scriptProcess
The ScriptProcess for sending commands.