Skip to content

Commit 9c466a5

Browse files
authored
3.5.0 (#25)
* Heartbeat and SystemManager overhaul * Asteroids, black holes, and mines now have their own classes; Consoles report how they can be claimed, you can send a Collection of packets, fixed a bug in the HeartbeatManager, blocks attempt to send a packet via an ArtemisNetworkInterface that isn't running; Ship now has a clone constructor; bases now handle their pitch, roll, and heading properties; fixed a bug when sending ArtemisPlayer objects; fixed a bug in retrieving a Vessel's torpedo tubes, added constructors for bases, players, and NPCs that will auto-populate some fields based on a Vessel or Ship; unknown properties can now be read or set individually; moved the side property to ArtemisShielded rather than BaseArtemisShip (so now bases have a side); fixed a concurrency issue with World; * Fixed a bug in base side parsing * Made certain parsing errors non-fatal * Minor comment tweaks * Made timeout more generous on ThreadedArtemisNetworkInterfaceTest to address false positives * System grid overhaul * ProxyDemo doesn't send duplicate heartbeat packets anymore * Pushed getVisibility() up to ArtemisObject * Minor tweaks * Updated documentation * Anomaly types now have human-readable names * Reworked ENEMY or OTHER detection to use sides first * Updated scan handling, added getNameString(), removed isEnemy(), tag support, WorldListeners * Fixed #9 * Fixed #24 * Fixed problem with computing fractional positions between grid points * BiomechRagePacket and TensionPacket * PausePacket now uses a simple boolean rather than a BoolState * ServerDiscoveryResponder now reports username for host like Artemis does * Added BoolState.toValue() * Fixed problems with Grid updates losing data * Code cleanup and documentation * ArtemisOrientable now extends ArtemisObject * ArtemisShielded now extends ArtemisOrientable * Fixed problem with improper undock detection * Added callsign extraction, getVessel() won't NPE if passed null Context * Updated tests * Fixed incorrect BeamFiredPacket parsing * Added <distributionManagement> * Renamed HOMING to TORPEDO to match terminology change in the game * Improved documentation and toString()s * Fixed copyNodes() bug that created inaccurate copies * Fixed error in comment
1 parent 7b30936 commit 9c466a5

File tree

132 files changed

+4030
-2259
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

132 files changed

+4030
-2259
lines changed

CONTRIBUTING.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
You want to contribute to IAN's development? That's awesome! 👍 Here's some information about how to best help:
22

33
### Report a bug or missing feature
4-
[Check to see if I already know about it.](https://github.com/rjwut/ian/issues) If not, [submit a new issue](https://github.com/rjwut/ian/issues/new). Be sure to include any relevant details. For example, a bug report should include 1) what you expected to happen 2) what actually happened, 3) a complete list of steps to reproduce the error, and 4) any error message you received (especially stack traces).
4+
[Check to see if I already know about it.](https://github.com/rjwut/ian/issues) If not, [submit a new issue](https://github.com/rjwut/ian/issues/new). Be sure to include any relevant details. For example, a bug report should include 1) a list of the specific steps which led to the error, 2) what you expected to happen, 3) what actually happened, 4) any error message you received (especially stack traces), and 5) any other information you believe would be helpful.
55

66
### Improve our knowledge of the Artemis protocol
77
If you're handy with a packet sniffer, you can be of great use helping us [document the Artemis protocol](https://github.com/artemis-nerds/protocol-docs). Create issues on that project with any information you discover (or, if you know HTML, you can submit a pull request on the documentation itself). Improvements to the protocol documentation are eventually implemented in IAN.
88

99
### Implement a feature or fix a bug
10-
Are you a Java developer? Feel free to implement a feature or bug fix for IAN yourself! Fork the repository, apply the changes to your copy, then submit a pull request. Note that we're trying to improve our testing coverage, so including unit tests would be appreciated.
10+
Are you a Java developer? Feel free to implement a feature or bug fix for IAN yourself! Fork the repository, apply the changes to your copy, then submit a pull request. Note, however, that any one version of IAN targets a specific version of *Artemis*, so be sure you aren't writing something that will be incompatible with the targeted version.

README.md

Lines changed: 59 additions & 15 deletions
Large diffs are not rendered by default.

pom.xml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
24
<modelVersion>4.0.0</modelVersion>
35
<groupId>com.walkertribe</groupId>
46
<artifactId>ian</artifactId>
5-
<version>3.4.0</version>
7+
<version>3.5.0</version>
68
<name>Interface for Artemis Networking (IAN)</name>
79
<description>UNOFFICIAL Java library for communicating with Artemis Spaceship Bridge Simulator servers and clients.</description>
810
<url>https://github.com/rjwut/ian</url>
@@ -25,6 +27,13 @@
2527
<url>https://github.com/rjwut/ian</url>
2628
<connection>scm:git:git://github.com/rjwut/ian.git</connection>
2729
</scm>
30+
<distributionManagement>
31+
<repository>
32+
<id>github</id>
33+
<name>GitHub Packages</name>
34+
<url>https://maven.pkg.github.com/rjwut/ian</url>
35+
</repository>
36+
</distributionManagement>
2837
<properties>
2938
<maven.compiler.source>1.7</maven.compiler.source>
3039
<maven.compiler.target>1.7</maven.compiler.target>

src/main/java/com/walkertribe/ian/Context.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package com.walkertribe.ian;
22

33
import com.walkertribe.ian.model.Model;
4+
import com.walkertribe.ian.util.Grid;
45
import com.walkertribe.ian.vesseldata.VesselData;
5-
import com.walkertribe.ian.vesseldata.VesselInternals;
66

77
/**
88
* Interface for classes which can return Artemis resources.
@@ -22,8 +22,8 @@ public interface Context {
2222
public Model getModel(String dxsPaths);
2323

2424
/**
25-
* Given the path to an .snt file, returns a VesselInternals object that
26-
* describes the node grid stored in that file.
25+
* Given the path to an .snt file, returns a Grid object that describes the
26+
* node nodes stored in that file. Grids returned by this method are locked.
2727
*/
28-
public VesselInternals getInternals(String sntPath);
28+
public Grid getGrid(String sntPath);
2929
}

src/main/java/com/walkertribe/ian/DefaultContext.java

Lines changed: 120 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package com.walkertribe.ian;
22

3+
import java.io.BufferedInputStream;
34
import java.io.IOException;
45
import java.io.InputStream;
6+
import java.io.OutputStream;
57
import java.net.MalformedURLException;
68
import java.util.HashMap;
79
import java.util.Map;
@@ -15,22 +17,31 @@
1517
import org.xml.sax.XMLReader;
1618
import org.xml.sax.helpers.DefaultHandler;
1719

20+
import com.walkertribe.ian.enums.ShipSystem;
1821
import com.walkertribe.ian.model.Model;
1922
import com.walkertribe.ian.model.SAXModelHandler;
23+
import com.walkertribe.ian.util.ByteArrayReader;
24+
import com.walkertribe.ian.util.Grid;
25+
import com.walkertribe.ian.util.GridCoord;
26+
import com.walkertribe.ian.util.GridNode;
2027
import com.walkertribe.ian.vesseldata.SAXVesselDataHandler;
2128
import com.walkertribe.ian.vesseldata.VesselData;
22-
import com.walkertribe.ian.vesseldata.VesselInternals;
2329

2430
/**
2531
* Context implementation that loads resources from a path using a provided
2632
* PathResolver, and caches the results.
2733
* @author rjwut
2834
*/
2935
public class DefaultContext implements Context {
36+
private static final int EMPTY_NODE_VALUE = -2;
37+
private static final int HALLWAY_NODE_VALUE = -1;
38+
private static final int BLOCK_SIZE = 32;
39+
private static final byte[] RESERVED = new byte[16];
40+
3041
private PathResolver pathResolver;
3142
private VesselData vesselData;
3243
private Map<String, Model> modelMap = new HashMap<String, Model>();
33-
private Map<String, VesselInternals> internalsMap = new HashMap<String, VesselInternals>();
44+
private Map<String, Grid> gridMap = new HashMap<String, Grid>();
3445

3546
/**
3647
* Creates a new Context using the given PathResolver.
@@ -82,20 +93,55 @@ public Model getModel(String dxsPaths) {
8293
}
8394

8495
/**
85-
* Given the path to an .snt file, returns a VesselInternals object that
86-
* describes the node grid stored in that file. The VesselInternals will be
87-
* cached in this object, and the cached VesselInternals will be used for
96+
* Given the path to an .snt file, returns a Grid object that describes the node nodes stored in
97+
* that file. The Grid will be cached in this object, and the cached Grid will be used for
8898
* subsequent requests for the same .snt file.
8999
*/
90-
public VesselInternals getInternals(String sntPath) {
91-
VesselInternals internals = internalsMap.get(sntPath);
100+
public Grid getGrid(String sntPath) {
101+
Grid grid = gridMap.get(sntPath);
92102

93-
if (internals == null) {
94-
internals = loadInternals(sntPath);
95-
internalsMap.put(sntPath, internals);
103+
if (grid == null) {
104+
grid = readSnt(sntPath);
105+
gridMap.put(sntPath, grid);
96106
}
97107

98-
return internals;
108+
return grid;
109+
}
110+
111+
/**
112+
* Outputs the given Grid as an .snt file. An IllegalStateException will be thrown if any node
113+
* is encountered which doesn't contain the required information.
114+
*/
115+
public void writeSnt(Grid grid, OutputStream out) throws IOException {
116+
final byte[] buffer = new byte[4];
117+
118+
for (int x = 0; x < GridCoord.MAX_X; x++) {
119+
for (int y = 0; y < GridCoord.MAX_X; y++) {
120+
for (int z = 0; z < GridCoord.MAX_X; z++) {
121+
GridCoord coord = GridCoord.get(x, y, z);
122+
writeFloat(buffer, out, coord.x());
123+
writeFloat(buffer, out, coord.y());
124+
writeFloat(buffer, out, coord.z());
125+
GridNode node = grid.getNode(coord);
126+
int type;
127+
128+
if (node == null || !node.isAccessible()) {
129+
type = EMPTY_NODE_VALUE;
130+
} else {
131+
ShipSystem system = node.getSystem();
132+
133+
if (system == null) {
134+
type = HALLWAY_NODE_VALUE;
135+
} else {
136+
type = system.ordinal();
137+
}
138+
}
139+
140+
writeInt(buffer, out, type);
141+
out.write(RESERVED);
142+
}
143+
}
144+
}
99145
}
100146

101147
/**
@@ -125,14 +171,55 @@ private Model loadModel(String dxsPaths) {
125171
}
126172

127173
/**
128-
* Creates and returns a VesselInternals object loaded from the indicated
129-
* .snt file.
174+
* Creates and returns a Grid object loaded from the indicated .snt file.
130175
*/
131-
private VesselInternals loadInternals(String sntPath) {
176+
private Grid readSnt(String sntPath) {
132177
InputStream in = null;
133178

134179
try {
135-
return new VesselInternals(pathResolver.get(sntPath));
180+
in = pathResolver.get(sntPath);
181+
182+
if (!(in instanceof BufferedInputStream)) {
183+
in = new BufferedInputStream(in);
184+
}
185+
186+
byte[] buffer = new byte[BLOCK_SIZE];
187+
final ShipSystem[] systems = ShipSystem.values();
188+
Grid grid = new Grid();
189+
190+
try {
191+
for (int x = 0; x < GridCoord.MAX_X; x++) {
192+
for (int y = 0; y < GridCoord.MAX_Y; y++) {
193+
for (int z = 0; z < GridCoord.MAX_Z; z++) {
194+
GridCoord coords = GridCoord.get(x, y, z);
195+
ByteArrayReader.readBytes(in, BLOCK_SIZE, buffer);
196+
ByteArrayReader reader = new ByteArrayReader(buffer);
197+
float shipX = reader.readFloat();
198+
float shipY = reader.readFloat();
199+
float shipZ = reader.readFloat();
200+
int type = reader.readInt();
201+
GridNode node;
202+
203+
if (type == EMPTY_NODE_VALUE) {
204+
node = new GridNode(grid, coords, shipX, shipY, shipZ, false);
205+
} else if (type == HALLWAY_NODE_VALUE) {
206+
node = new GridNode(grid, coords, shipX, shipY, shipZ, true);
207+
} else {
208+
node = new GridNode(grid, coords, shipX, shipY, shipZ, systems[type]);
209+
}
210+
211+
grid.setNode(node);
212+
}
213+
}
214+
}
215+
216+
grid.lock();
217+
return grid;
218+
} catch (InterruptedException ex) {
219+
throw new RuntimeException(ex);
220+
} catch (IOException ex) {
221+
throw new RuntimeException(ex);
222+
}
136223
} catch (MalformedURLException ex) {
137224
throw new RuntimeException(ex);
138225
} catch (IOException ex) {
@@ -168,4 +255,22 @@ private void parseXml(String path, DefaultHandler handler) {
168255
throw new RuntimeException(ex);
169256
}
170257
}
258+
259+
/**
260+
* Writes a float value to the given OutputStream.
261+
*/
262+
private static void writeFloat(byte[] buffer, OutputStream out, float v) throws IOException {
263+
writeInt(buffer, out, Float.floatToRawIntBits(v));
264+
}
265+
266+
/**
267+
* Writes an int value to the given OutputStream.
268+
*/
269+
private static void writeInt(byte[] buffer, OutputStream out, int v) throws IOException {
270+
buffer[0] = (byte) (0xff & v);
271+
buffer[1] = (byte) (0xff & (v >> 8));
272+
buffer[2] = (byte) (0xff & (v >> 16));
273+
buffer[3] = (byte) (0xff & (v >> 24));
274+
out.write(buffer, 0, 4);
275+
}
171276
}

src/main/java/com/walkertribe/ian/enums/AnomalyType.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,26 @@
55
* @author rjwut
66
*/
77
public enum AnomalyType {
8-
HIDENS_POWER_CELL(Upgrade.HIDENS_POWER_CELL),
9-
VIGORANIUM_NODULE(Upgrade.VIGORANIUM_NODULE),
10-
CETROCITE_HEATSINKS(Upgrade.CETROCITE_HEATSINKS),
11-
LATERAL_ARRAY(Upgrade.LATERAL_ARRAY),
12-
TAURON_FOCUSERS(Upgrade.TAURON_FOCUSERS),
13-
INFUSION_P_COILS(Upgrade.INFUSION_P_COILS),
14-
CARPACTION_COILS(Upgrade.CARPACTION_COILS),
15-
SECRET_CODE_CASE(Upgrade.SECRET_CODE_CASE),
16-
BEACON,
17-
SPACE_JUNK;
8+
HIDENS_POWER_CELL("HiDens Power Cell", Upgrade.HIDENS_POWER_CELL),
9+
VIGORANIUM_NODULE("Vigoranium Nodule", Upgrade.VIGORANIUM_NODULE),
10+
CETROCITE_HEATSINKS("Cetrocite Crystal", Upgrade.CETROCITE_HEATSINKS),
11+
LATERAL_ARRAY("Lateral Array", Upgrade.LATERAL_ARRAY),
12+
TAURON_FOCUSERS("Tauron Focusers", Upgrade.TAURON_FOCUSERS),
13+
INFUSION_P_COILS("Infusion P-Coils", Upgrade.INFUSION_P_COILS),
14+
CARPACTION_COILS("Carapaction Coils", Upgrade.CARPACTION_COILS),
15+
SECRET_CODE_CASE("Secret Code Case", Upgrade.SECRET_CODE_CASE),
16+
BEACON("Beacon"),
17+
SPACE_JUNK("Space Junk");
1818

19+
private String name;
1920
private Upgrade mUpgrade;
2021

21-
private AnomalyType() {
22-
// for beacons and space junk
22+
private AnomalyType(String name) {
23+
this.name = name;
2324
}
2425

25-
private AnomalyType(Upgrade upgrade) {
26+
private AnomalyType(String name, Upgrade upgrade) {
27+
this(name);
2628
mUpgrade = upgrade;
2729
}
2830

@@ -33,4 +35,9 @@ private AnomalyType(Upgrade upgrade) {
3335
public Upgrade getUpgrade() {
3436
return mUpgrade;
3537
}
38+
39+
@Override
40+
public String toString() {
41+
return name;
42+
}
3643
}

src/main/java/com/walkertribe/ian/enums/CommsRecipientType.java

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package com.walkertribe.ian.enums;
22

33
import com.walkertribe.ian.Context;
4-
import com.walkertribe.ian.util.BoolState;
4+
import com.walkertribe.ian.vesseldata.Faction;
55
import com.walkertribe.ian.vesseldata.Vessel;
66
import com.walkertribe.ian.world.ArtemisNpc;
77
import com.walkertribe.ian.world.ArtemisObject;
8+
import com.walkertribe.ian.world.ArtemisPlayer;
89

910
/**
10-
* The types of ArtemisObjects to which players can send COMMs messages.
11+
* The types of ArtemisObjects to which players can send COMMs messages.
1112
* @author rjwut
1213
*/
1314
public enum CommsRecipientType {
@@ -49,27 +50,42 @@ public CommsMessage messageFromId(int id) {
4950
};
5051

5152
/**
52-
* Returns the CommsRecipientType that corresponds to the given
53-
* ArtemisObject; or null if the object in question cannot receive COMMs
54-
* messages.
53+
* Returns the CommsRecipientType that corresponds to the given ArtemisObject;
54+
* or null if the object in question cannot receive COMMs messages. In the
55+
* case of an NPC, the CommsRecipient type might be ENEMY or OTHER; which one
56+
* is determined by checking to see if they are on the same side as the
57+
* player. In the rare case that one or both of the sides are unknown, it will
58+
* fall back on using the Context to retrieve the NPC's faction and checking
59+
* see if it has the ENEMY attribute. If neither method works, fromObject()
60+
* throw an IllegalStateException.
5561
*/
56-
public static CommsRecipientType fromObject(ArtemisObject obj, Context ctx) {
57-
ObjectType type = obj.getType();
62+
public static CommsRecipientType fromObject(ArtemisPlayer sender, ArtemisObject recipient, Context ctx) {
63+
ObjectType type = recipient.getType();
5864

5965
switch (type) {
6066
case PLAYER_SHIP:
6167
return PLAYER;
6268
case BASE:
6369
return BASE;
6470
case NPC_SHIP:
65-
ArtemisNpc npc = (ArtemisNpc) obj;
66-
Vessel vessel = npc.getVessel(ctx);
67-
boolean enemy;
71+
ArtemisNpc npc = (ArtemisNpc) recipient;
72+
Boolean enemy = null;
73+
byte senderSide = sender.getSide();
74+
byte recipientSide = npc.getSide();
6875

69-
if (vessel != null) {
70-
enemy = vessel.getFaction().is(FactionAttribute.ENEMY);
71-
} else {
72-
enemy = BoolState.safeValue(npc.isEnemy());
76+
if (senderSide != -1 && recipientSide != -1) {
77+
enemy = senderSide != recipientSide;
78+
} else if (ctx != null) {
79+
Vessel vessel = npc.getVessel(ctx);
80+
Faction faction = vessel.getFaction();
81+
82+
if (faction != null) {
83+
enemy = faction.is(FactionAttribute.ENEMY);
84+
}
85+
}
86+
87+
if (enemy == null) {
88+
throw new IllegalStateException("Cannot determine if recipient is enemy");
7389
}
7490

7591
return enemy ? ENEMY : OTHER;
@@ -82,4 +98,4 @@ public static CommsRecipientType fromObject(ArtemisObject obj, Context ctx) {
8298
* Returns the CommsMessage value that corresponds to the given message ID.
8399
*/
84100
public abstract CommsMessage messageFromId(int id);
85-
}
101+
}

0 commit comments

Comments
 (0)