The online racing simulator
My next feature-request is an abstraction of creating "compound" buttons i.e. buttons which are grouped together by a non-clickable background button.

It's basically similar to html tables: rows and columns, with rowspan and columnspan. Hey, wouldn't it be dreamy if I could define my LFS user interface by simply editing a html table (xml code), and it would be generated for me?
I've found some things to correct in net.sf.jinsim.Encoding.

Some of the lfs-escaped characters are missing (maybe they were introduced in a recent version?):


<?php 
case 'v':
    
result.append('|');
    break;
case 
'h':
    
result.append('#');
    break;
?>

The < and > escaped characters are wrong, this is there:

<?php 
case '<':
    
result.append('<');
    break;
case 
'>':
    
result.append('>');
    break;
?>

but this should be there:

<?php 
case 'l':
    
result.append('<');
    break;
case 
'r':
    
result.append('>');
    break;
?>

While I'm at it, let me mention that the Korean, and Chinese charsets are missing from Encoder.
Note to self: it would be more ideal if JInSim distribution jar filename also had the version number of the lfs version it supports.
For my changelog:
- a new entry was needed in net.sf.jinsim.Track:
BLACKWOOD_CAR_PARK("022", "Blackwood Car Park", "BL3", 0),

- net.sf.jinsim.response.relay createHostInfo method needs to be updated to support S1, S2, first, last flags:

boolean S1 = (flags & 4) > 0;
boolean S2 = (flags & 8) > 0;
boolean first = (flags & 64) > 0;
boolean last = (flags & 128) > 0;

Accordingly, HostInfo needs these fields as members, and as constructor arguments.
I was thinking about how could I get rid of the instanceof checks in JInSimListeners. I've been reading about pros and cons of using instanceof checks, and I've found that it's fine if I want to switch between a couple object types, but it doesn't scale well, if the number of types is bigger.

For example, if I have ten different types of packets coming in, in case of the tenth, nine extra instanceof condition-check is needed, for every single packet.

To make it worse, if I want to have more, and specialized Listeners ("high cohesion"), I have to give every packet to every Listener, so a packet will be checked for type many times. *OR* I could create one big central control Listener to dispatch all packets between specialized Listeners, but that would need as many instanceof checks as many types we have (it would be really bad for the ones that happened to get at the end of the condition-check list.


Looking for an alternative solution, I've found that *Visitor pattern* is generally recommended for this situation.

The big pro for Visitor is the fact that I, as the user of JInSim library, can make one (or any number, as needed) special Visitor (or as I like to call it: "Processor") class for every packet type I need to handle.

At runtime, there's no need for any instanceof checks, every packet is directly dispatched to the proper Visitor object by Java's polymorphic method selection mechanism between superclass and subclass Visitors.

The con for Visitor is that I have to modify the code of each packet class, and create the Visitor interface with as many visit() methods, as many types we have. That would be fine in itself, but if I want my modified JInSim library to support a new type of packet later, I would have to modify this interface too. (And the abstract adapter class as well, which would be positioned between the Visitor interface and the Visitor implementations, so that implementations need to implement only one "visit" method.)


This is my current understanding of the factors of this problem. I hope I can come up with a proof of concept version soon.
This changes the picture of the current Observer pattern: a "give-me every type and let me typecheck" Listener could co-exist with a "call-me when I'm needed" Visitor, but it would be easier to just write Visitor classes, and subscribe *them* to the Client.


I'm thinking of this problem while keeping in mind that packets can also be separated between handling classes by their Request ID-s.
So essentially, a request ID aware client could dispatch packets by their ID-s, and their types at the same time, without extra typechecks at RUNTIME!
About naming (and not shaming...)

I have implemented the Visitor pattern I mentioned, and it worked out great. It took me some time however, to come up with just the right class/interface names. First I called my Visitors "Processor", and the Visitable "Processable", but then I realized that a better name would be "Receiver" and "Receivable".

Especially because I could mark other packets as Sendable (and of course I could have packets which are both Sendable and Receivable.

I turned my attention to the packet factory mechanism, which is a really nice implementation of the factory pattern, but I've found some things I don't like. E.g. the fact that it has to iterate through the packet types twice: once for finding out the packet type, then to check if it is "registered". ("Registered" meaning it is receivable.)
The other thing I don't like is that there are "Requests" and "Responses", but the InSim protocol is a little bit more distinguished than that: there are "info request", "info", "both ways" (meaning both info request and info), and "instruction" (which are requests that don't get responded).

Currently I have these group names in mind:
- "inbound": for the "info" packets; these can be marked with "Receivable" interface
- "outbound": for the "info request" and "instruction" packets; these can be marked with "Sendable" interface
- "duplex": for the "both ways" packets (I don't want to implement a "both way" twice: once as a request and once as a response); these can be marked with both the "Receivable" and the "Sendable" interfaces.

I'm in the process of evaluating these ideas. Hopefully, I'll have some results to show for it soon.
For someone who would like to bring JInSim up to date, these notes might be useful:

- I can see that in the 06B svn branch, net.sf.jinsim.PacketType already has the new types:
CONTACT_CAR_OBJECT(51),
REPORT_HLVC_VIOLATION(52),
PLAYER_CARS(53),
AUTOCROSS_OBJECTS(54),
ADMIN_COMMAND_REPORT(55),

However, net.sf.jinsim.request.InitRequest doesn't have the flag constants for these: (quote from InSim.txt IS_ISI struct)
#define ISF_OBH 128 // bit 7 : receive OBH packets
#define ISF_HLV 256 // bit 8 : receive HLV packets
#define ISF_AXM_LOAD 512 // bit 9 : receive AXM when loading a layout
#define ISF_AXM_EDIT 1024 // bit 10 : receive AXM when changing objects

- InSim.txt says at struct IS_STA:
#define ISS_VISIBLE 16384 // InSim buttons visible

But net.sf.jinsim.response.StateResponse doesn't have this flag constant.

- struct IS_STA has this section in InSim.txt:
byte RaceLaps; // see "RaceLaps" near the top of this document
byte Spare2;
byte Spare3;

char Track[6]; // short name for track e.g. FE2R

However, net.sf.jinsim.response.StateResponse has this section in its construct method:
setNumLaps(new RaceLaps(buffer));
setShortTrackName(getString(buffer, 6));

Meaning the two spare bytes are not getting skipped!
net.sf.jinsim.AbstractChannel says this:


<?php 
if (size && buffer.position() == size) {
?>

I'm wondering whether it should be like this:


<?php 
if (size && buffer.position() >= size) {
?>

I'm thinking, what if the buffer receives more than one packet's bytes within the same cycle of the forever running loop. buffer.position() will never be equal to size then...

If that can happen, the next packet size reading would be in trouble (either missing whole packet or packets, or worse, reading an arbitrary byte from the middle of a packet)...
Quote from szaboaz :I'm thinking, what if the buffer receives more than one packet's bytes within the same cycle of the forever running loop. buffer.position() will never be equal to size then...

If that can happen, the next packet size reading would be in trouble (either missing whole packet or packets, or worse, reading an arbitrary byte from the middle of a packet)...

With TCP / UDP connections, there can be times where you only get a single byte of the packet. For this reason, the first byte of every InSim packet is the size, and all of the packets are less then 256 bytes. So as long as your not getting corrupted packets, you should always know when you have an whole packet to parse.
Quote from szaboaz :
If that can happen, the next packet size reading would be in trouble (either missing whole packet or packets, or worse, reading an arbitrary byte from the middle of a packet)...

It's been a long while since I touched Java, but the basic principles should be universal. LFS indeed can and will send multiple packets in one burst, you just have to deal with that In my C(++) tools I something of this sort


char buffer[SIZE];
ssize_t bytes = 0;
while {
bytes = recv(sock, buffer + bytes, SIZE - bytes, 0);
while (buffer[0] <= bytes) {
handle_packet(buffer);
bytes -= buffer[0];
memmove(buffer, buffer + buffer[0], bytes);
}
}

I wrote the code off the top of my head so do check if it's correct It can also be further optimized by doing memmove() only when all complete packets are handled.
Thanks guys, I think I get it now. I just have to find the One Java Way now. ;-)

I did looked into the InSimDotNet.2.0.14b sources, though I'm quite innocent in .NET , I think I could make two conclusions from what I've seen.

1st is that I have to prepare for
- no bytes
- some bytes of a packet
- a packetful of bytes
- one (or more) packetful of bytes
- one (or more) packetful of bytes and then some bytes

The current implementation doesn't seem to support more bytes at one read, neither a packet and then some. (That is if I'm reading it right.)

The second was the callback mechanism. The solution that is currently applied in JInSim's AbstractChannel class is based on a continously running loop doing 10 ms sleeps, and polling the SocketChannel in every loop for new bytes.

I can already see, that the callback mechanism is objectively better, because
- the program can react instanteneously when new bytes arrive (otherwise, in worst case, I can loose up to 10 ms right there)
- it can avoid unnecessary loops, so less processor cycles are needed.

I already found that there is a mechanism for this provided by the Java SocketChannel API, it's my turn to learn, how to utilize it.


Thanks again for the attention.
Hi. I am developing an android application (GPL3 licensed) and I am interested in using main/java/net/sf/jinsim/Encoding.java module of JInSim library. However according to this https://www.gnu.org/licenses/license-list.en.html#MPL I am not really

Quote : That is, a module covered by the GPL and a module covered by the MPL cannot legally be linked together

Can I get that file with MPL 2.0 (which is compatible) or is there any other way I can incorporate the class in my project?
Unfortunately, the GPL is insidious by design. This is part of the reason why I use the MIT license on my projects.
I have moved the jinsim code now to github: https://github.com/openbakery/jinsim

Note: I have renamed the packages from net.sf to org.openbakery (Maybe we could also use net.lfs if the devs are ok with this)

I have not yet created a binary, but a simple 'gradle jar' will create one. (You need to have installed gradle see http://grade.org)

I have also updated the Tracks class to support the new Westhill configs.

(To a moderator: I think it would make sense to create a new JInSim thread here, because I cannot edit the first post, but I find it useful that the first post include latests informations.)
Quote from Brilwing :I have moved the jinsim code now to github: https://github.com/openbakery/jinsim

Note: I have renamed the packages from net.sf to org.openbakery (Maybe we could also use net.lfs if the devs are ok with this)

I have not yet created a binary, but a simple 'gradle jar' will create one. (You need to have installed gradle see http://grade.org)

I have also updated the Tracks class to support the new Westhill configs.

(To a moderator: I think it would make sense to create a new JInSim thread here, because I cannot edit the first post, but I find it useful that the first post include latests informations.)

Gradle link is wrong (you point to grade.org not gradle.org!)

You write that there is a dist directory, but in the zip archiv nor on github itself no such directory exists.

FGED GREDG RDFGDR GSFDG