The online racing simulator
Searching in All forums
(26 results)
1
szaboaz
Demo licensed
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.
szaboaz
Demo licensed
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)...
Last edited by szaboaz, .
szaboaz
Demo licensed
For the sake of fellow people who will search for this:

VIEW_MAX seems to provide the same function in "View identifiers" (camera type) enum.
szaboaz
Demo licensed
Oh, I see!
Thanks for the explanation.

Arpad
InSim.txt enum members with _NUM ending??
szaboaz
Demo licensed
Hi, could you help me out, please?

In InSim.txt I see these Enum members, but I can't figure out, what are they for (they don't have comment after them, they are always the last enum):
MSO_NUM
SND_NUM
VOTE_NUM
PITLANE_NUM
PSE_NUM
LEAVR_NUM
PENALTY_NUM
PENR_NUM
TYRE_NUM
PMO_NUM
DL_NUM

Thanks,
Arpad
szaboaz
Demo licensed
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!
Last edited by szaboaz, .
szaboaz
Demo licensed
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.
szaboaz
Demo licensed
"I am using my grandad's pants"
It's pretty funny, though. Even if I take into consideration the fact that it wasn't me who said it (aand I dunno who was). :P

You better have a good amount of humour if you wanna enjoy the beauties of the WORLD WIDE -web- LFS.
Last edited by szaboaz, .
szaboaz
Demo licensed
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!
Last edited by szaboaz, .
szaboaz
Demo licensed
Whoa, looks great!

I'm just scratching InSim programming, so help me to understand this conceptionally, please. This extension is useful for *client-side* InSim programs, isn't it? Or can it be useful for example to construct a tracker's UI too?

PS. Just a friendly heads up for another non native English speaker: "Object hitted" is grammatically incorrect, because the past tense and past participle of the verb "hit" is "hit". (You know: hit, hit, hit.)
Last edited by szaboaz, .
szaboaz
Demo licensed
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.
szaboaz
Demo licensed
Thank you very much.

My faith has been restored.
(And I learned a lesson, again... always, always, always insim.txt first :shy
Color codes still stripped from IS_MSO packets?
szaboaz
Demo licensed
My search for "MSO colour" have found this post by Scawen from 2007:
https://www.lfsforum.net/showt ... ght=mso+colour#post430986


Still no colors?

How can "less information" be better for an export function than "more information"?

I can see another potential problem with stripping colors (this without trying out anything): http://en.lfsmanual.net/wiki/FAQ says "^9 - Original text colour and codepage". If ^9 is stripped too (or is it not?), how can we be sure what codepage should be used?
szaboaz
Demo licensed
Note to self: it would be more ideal if JInSim distribution jar filename also had the version number of the lfs version it supports.
Last edited by szaboaz, .
szaboaz
Demo licensed
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.
Last edited by szaboaz, .
szaboaz
Demo licensed
Well, this conversation turned out to be somewhat single-sided, but I hope that it will help someone someday.

I've changed my latest method (I believe this will be the last change) so that
- at one wheel button press the feedback button (which rather serves as a label) appears and stays permanently on screen, until either
- the same wheel button is pressed which executes my customized admin command
- another wheel button is pressed, which revokes the action.

This makes it possible to wait for the very last moment (e.g. with a !spec command) not worrying about the timer. And if it's not necessary, just dismiss the warning without taking any action.
szaboaz
Demo licensed
Since all three approaches I devised so far leave something to be desired, I think I will go with a fourth one, which goes like this.

1. User presses wheel button (assigned to a "/o mycommand" text command, also with an Alt+ or Ctrl+ keyboard combination)
2. A non-clickable button comes up with the feedback. This serves as a confirmation and sports a countdown back from (let's say) five to zero by the second.
3. If user presses the wheel button again before this button disappears, the confirmed command will go through, otherwise nothing happens.

Nice or what.
Last edited by szaboaz, .
szaboaz
Demo licensed
I was exploring my "/press T"->show message entry dialog->type in text idea.

Since the clipboard technique doesn't work for escaped characters, I had another idea of simulating keyboard presses from my program.

I can "type" into the message box, I can even "press" Ctrl+1-9 for color codes.

However, I can't change codepages from keyboard only (by key combinations), so I'm stuck again.


Any other idea, how could I put text into the dialog (with colors/codepages/escaped characters correctly appearing)?
Last edited by szaboaz, .
szaboaz
Demo licensed
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?
szaboaz
Demo licensed
Sweet Jesus, dear admin, you deleted the *other* one instead of this. (Or was it merged, so the housekeeping conversation appears here?) Oh well, me and my adventures...

Okay, on topic then.

I've discovered a couple of potential approaches to this problem. Still not perfect, but getting there.

The first one was, since I didn't really need the pre-typed in message to be editable, I just wanted a "confirm" button (the message is supposed to be an admin command with the actual player's name). So I created a "compound" button, just like the message entry dialog, without the text field: nice big "Cancel" and "OK" buttons side by side, over a common background button. A picture serves better:

My only problem with this is that I have to use the mouse for pressing the buttons. I'd rather like if Enter worked for OK, Esc for Cancel, just like for the text entry Dialog.
How can I do that?


In the meantime, I've discovered, that I can send a "/press T" message, which results in the message entry dialog box popping up. I still have to figure out though, how to put my message into the textfield.

I've tried sending consecutive "/press a" "/press b" etc. commands, but the letters didn't end up in the textfield.

Sending "/ctrl v" after putting my message to system clipboard does fill the textfield, so it's almost perfect. Almost, because escape codes are shown instead of being interpreted.
I'm not sure if LFS clipboard allows escape coded text to be copied in-out...
Last edited by szaboaz, .
szaboaz
Demo licensed
Some handy tips for button users (maybe this could go into net.sf.jinsim.examples.button.Main):

When you want to create text entry dialogs (typeIn buttons), and initialize them with some text at the same time, you can do this (in Java 7 you can use binary literals, very handy when dealing with bit patterns):


//Set the texts
//this will be on the button, and also in the text entry dialog as initialized text
String typeInText = "typeInText";
//the title of the text entry dialog
String buttonTitleText = "titleText";
buttonRequest.setText("\u0000"+buttonTitleText+"\u0000"+typeInText);

//Enable typeIn button
//This would enable typeIn type button, but nothing appears in the text entry box
//because the character number has to be larger than the length of typeInText
//buttonRequest.setTypeIn( (byte) 0b1000_0000 ); //0 character

//This is the maximum value
buttonRequest.setTypeIn( (byte) 0b1101_1111 ); //95 character

And for the sake of nice readable code, I can do it like this:

byte TYPE_IN = (byte) 0b1000_0000;
//Or without binary literal:
//byte TYPE_IN = (byte) -128;
int typeInTextLength = 95;
buttonRequest.setTypeIn( (byte)(typeInTextLength | TYPE_IN) );

Last edited by szaboaz, .
szaboaz
Demo licensed
Quote from Dygear :I moved it for you.

Thanks. But now there's two of them, because I double posted. That was mistake No 2, I guess. Sorry.

Can you delete this thread, so the other remains intact (no answer in either)? Thank you.
Opening text entry dialog directly or by keyboard shortcut
szaboaz
Demo licensed
Edit:
Ouch, am I green or what. I intended to post this in the general programmer forum. Forum admin, could you please delete it from here? Thanks and sorry for the noise.

Edit2: Okay, this thread is the one to stay. Here we go.

****
Is it possible to open the text entry dialog directly (without clicking on a button first)?

If not, is there a way to activate ("click on") a button by an Alt+ or Ctrl+ key combination/shortcut? In that case I could create an "invisible" button, and assign the shortcut to that.


What I'm trying to accomplish is this: by pressing a keyboard shortcut (or a wheel button) a text entry dialog should come up with some text already typed in.
Last edited by szaboaz, .
szaboaz
Demo licensed
I have some ideas so I write them here mainly for the record, but comments or guidance are welcome.

Shouldn't the client fire some event when its channel goes down?
Edit: When I was using UDPChannel, and I closed LFS, my connected client's isConnected still reported "true". No such problem with TCPChannel.

Maybe regular (re)connection attempts could also be part of the library.

Edit:
Also, keeping an up-to-date list of currently connected people with on-track off-track status indication seems like a common requirement. (And not a trivial one at that, AFAICT.)

Edit:
Message/names encoding-decoding (codepages, color codes, escaped characters), maybe it's in there, I just haven't stumbled upon it yet.

Edit:
I've not only found the Encoding class, but already caught a bug (missing feature) in it. There's this line in encodeString(String text) method:

<?php 
if (ch && ch 128) {
?>

This exludes the zero character '\0' a.k.a. '\u0000', which is a problem, because zero characters are needed for initializing text in button text entry dialogues. Excerpt from insim.txt:
// On clicking the button, a text entry dialog will be opened, allowing the specified number of
// characters to be typed in. The caption on the text entry dialog is optionally customisable using
// Text in the IS_BTN packet. If the first character of IS_BTN's Text field is zero, LFS will read
// the caption up to the second zero. The visible button text then follows that second zero.

// Text : 65-66-67-0 would display button text "ABC" and no caption

// Text : 0-65-66-67-0-68-69-70-71-0-0-0 would display button text "DEFG" and caption "ABC"

I'm inclined to change that line to this:

<?php 
if (ch 128) {
?>

This includes 0 (and no need to check the lower boundary, since chars' minimum value is zero). I wonder what was the reason behind excluding it in the first place...
Last edited by szaboaz, .
szaboaz
Demo licensed
Why do TinyRequest and SmallRequest default to RequestInfo (reqI) 254?

Edit: oh, I can see it now. LFS reports "InSim : TINY_PING with no ReqI - QuickSpec" if it was sent with reqI = 0. Maybe it's there somewhere in the documentation?

Edit: ah, there it is in InSim.txt:
// ReqI : non-zero (returned in the reply)
// SubT : TINY_PING (request a TINY_REPLY)

Now I just need to find out, why is it 254 (why not 255, e.g.) ?
Last edited by szaboaz, .
1
FGED GREDG RDFGDR GSFDG