Elvas Tower: Expand potential of TCS scripting - Elvas Tower

Jump to content

Posting Rules

All new threads will be started by members of the Open Rails team, Staff, and/or Admins. Existing threads started in other forums may get moved here when it makes sense to do so.

Once a thread is started any member may post replies to it.
  • 9 Pages +
  • « First
  • 5
  • 6
  • 7
  • 8
  • 9
  • You cannot start a new topic
  • You cannot reply to this topic

Expand potential of TCS scripting Rate Topic: -----

#91 User is offline   Serana 

  • Conductor
  • Group: Posts: Contributing Member
  • Posts: 489
  • Joined: 21-February 13
  • Gender:Male
  • Location:St Cyr l'Ecole (France)
  • Simulator:Open Rails
  • Country:

Posted 30 August 2020 - 08:49 AM

On the MSFS (and FSX and Prepar3D) side, they are using a library called SimConnect as an interface between the flight simulator and the "scripts".
Well, they are not really scripts since they must be compiled.
If the code is executed out of the flight sim process, the developers can use C, C++; C# and VB.Net.
If the code is executed inside of the flight sim process, the developers can only use C++ and compile into WebAssembly format.

SimConnect C++ library is basically composed of functions without classes (procedural programming).
For example, in order to get access to a variable of the aircraft, you have to write this for example:


static enum DATA_DEFINE_ID {
  DEFINITION_1,
  DEFINITION_2
};

static enum DATA_REQUEST_ID {
    REQUEST_1,
    REQUEST_2,
};

struct Struct1
{
    double  kohlsmann;
    double  altitude;
    double  latitude;
    double  longitude;
};
// Match string definitions from the Simulation Variables document with the client defined ID

hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Kohlsman setting hg", "inHg");
hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Indicated Altitude", "feet");
hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Plane Latitude", "degrees");
hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "Plane Longitude", "degrees");

// Sections of code in DispatchProc

....
SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_2, DEFINITION_1, SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD_SECOND);
....
// When the data is received -- cast it to the correct structure type

case SIMCONNECT_RECV_ID_SIMOBJECT_DATA:
{
  SIMCONNECT_RECV_SIMOBJECT_DATA *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA*) pData;

  switch(pObjData->dwRequestID)
  {
    case REQUEST_2:

      Struct1 *pS = (Struct1*)&pObjData->dwData;
   
      // Add code to process the structure appropriately

      break;
  }
break;
}
....



It's a mess...

For gauges, things are a bit easier since it does not use SimConnect.
For example, to get a variable:
struct sCompassVars
{
	NVGcontext* m_nvgctx = nullptr;
	ENUM m_eDegrees;
	ENUM m_ePlaneHeadingDegreesTrue;
	int m_iFont;
};

sCompassVars g_CompassVars;

...
g_CompassVars.m_eDegrees = get_units_enum("DEGREES");
g_CompassVars.m_ePlaneHeadingDegreesTrue = get_aircraft_var_enum("PLANE HEADING DEGREES TRUE");
FLOAT64 fHeading = aircraft_varget(g_CompassVars.m_ePlaneHeadingDegreesTrue, g_CompassVars.m_eDegrees, 0);
...


Much better. But not every gauges are written in C++.
A new way of creating gauges has been introduced in MSFS: the gauges are written in HTML, CSS and JS.
I'll try to find a way to use this approach for Open Rails.

#92 User is offline   gpz 

  • Superintendant
  • Group: Posts: Elite Member
  • Posts: 1,846
  • Joined: 27-October 12
  • Gender:Male
  • Location:Budapest
  • Simulator:OpenRails
  • Country:

Posted 30 August 2020 - 09:52 AM

Oh, no, it isn't necessary. :) I'm not convinced yet, that it is any better than what we are using now. :) But thank you for the examples, it is a good insight! Definitely we need to continue the C# way, and I am not convinced that involving html/css/js would bring us any good either. :)

#93 User is offline   Serana 

  • Conductor
  • Group: Posts: Contributing Member
  • Posts: 489
  • Joined: 21-February 13
  • Gender:Male
  • Location:St Cyr l'Ecole (France)
  • Simulator:Open Rails
  • Country:

Posted 30 August 2020 - 10:14 AM

For HTML/CSS/JS, that's only for things that will be rendered on the cabview (like the gauges in MSFS).
It's is easier to create GUI with web technologies than with XNA/MonoGame/DirectX rendering.




#94 User is offline   gpz 

  • Superintendant
  • Group: Posts: Elite Member
  • Posts: 1,846
  • Joined: 27-October 12
  • Gender:Male
  • Location:Budapest
  • Simulator:OpenRails
  • Country:

Posted 30 August 2020 - 10:14 AM

If I interpret it well, the first one is a kind of a "subscribe-on-data-stream" with a predefined update interval, where the update() function must be started with processing the data "pushed", right?

#95 User is offline   gpz 

  • Superintendant
  • Group: Posts: Elite Member
  • Posts: 1,846
  • Joined: 27-October 12
  • Gender:Male
  • Location:Budapest
  • Simulator:OpenRails
  • Country:

Posted 30 August 2020 - 11:27 AM

 Serana, on 30 August 2020 - 10:14 AM, said:

For HTML/CSS/JS, that's only for things that will be rendered on the cabview

Ah, sorry, I thought you are mentioning the scripting part.

#96 User is offline   gpz 

  • Superintendant
  • Group: Posts: Elite Member
  • Posts: 1,846
  • Joined: 27-October 12
  • Gender:Male
  • Location:Budapest
  • Simulator:OpenRails
  • Country:

Posted 30 August 2020 - 11:37 AM

 cesarbl, on 30 August 2020 - 01:03 AM, said:

However, the addition of this signals isn't enough when simulating continuous systems like LZB or ETCS L2, where ideally there should be a script running at trackside, communicating with the on-board script. For these systems, deeper signalling and track information is needed.

This is what Rob was talking about on the 1st page. We must hope, that if he develops the described new track circuit logic and signals with abilities to interact with the trains in his own version of OpenRails, he is willing to share that with us.

#97 User is online   mrmosky 

  • Foreman Of Engines
  • Group: Posts: Contributing Member
  • Posts: 811
  • Joined: 02-October 16
  • Gender:Male
  • Location:Chasetown
  • Simulator:Openrails
  • Country:

Posted 30 August 2020 - 01:22 PM

I don't understand most of the above, but when you are talking about cabviews, are you also including 3d cabs?

I am asking this as I have a particular interest in this and feel that 3d cabs are the way forward.

Geoff

#98 User is offline   Serana 

  • Conductor
  • Group: Posts: Contributing Member
  • Posts: 489
  • Joined: 21-February 13
  • Gender:Male
  • Location:St Cyr l'Ecole (France)
  • Simulator:Open Rails
  • Country:

Posted 30 August 2020 - 03:08 PM

Yes, of course. For me, cabviews include 2D and 3D.

#99 User is offline   gpz 

  • Superintendant
  • Group: Posts: Elite Member
  • Posts: 1,846
  • Joined: 27-October 12
  • Gender:Male
  • Location:Budapest
  • Simulator:OpenRails
  • Country:

Posted 05 September 2020 - 02:28 AM

This weekend I have a chance to take a look on the code by a real computer (till now I was just browsing it via a mobile phone :) ). I haven't decided yet if I want to come back coding, but I feel more that I have to make some adjustments to this part. The current code in some aspects seems unfinished (beyond the big unfinishment of at some point just dropping Locomotive() in, instead of designing proper interface functions). For example the following code works only in lucky cases:
        T NextDivergingSwitchItem<T>(float maxDistanceM, ref T retval, Train.TrainObjectItem.TRAINOBJECTTYPE type)
        {
            var LocalTrainInfo = Locomotive.Train.GetTrainInfo();
            SignalDistance = float.MaxValue;
            foreach (var foundItem in Locomotive.Train.MUDirection == Direction.Reverse ? TrainInfo.ObjectInfoBackward : TrainInfo.ObjectInfoForward)
            {

There's an unused LocalTrainInfo object created at every function call, even if the function is called multiple times in a script (spinning the garbage collector). Instead correctly, the once-per-frame created TrainInfo object is used, but currently this is only created in the NextSignalItem() function, so if the NextDivergingSwitchItem() above is called fist in a script, it would not yet have a working TrainInfo object to search in.

I also don't understand, why a distinct Train.NextTrailingDivergingSwitchDistanceM() function was created, instead of extending the TrainInfo class to contain these objects too. Facing switches are contained, but trailing switches aren't. Is there a particular reason it was done this dirty way? If there is no particular reason for that, then my intention is to fix this. (Actually the same question applies for the generic signals too, I need more investigation. If I finally get enough time for OpenRails.) I would also like to add the missing interfaces, so that the improper Locomotive() could be removed once and forever.

I think the code review process did not work particularly well for the PR-s of this feature, but knowing that there are so few active developers around, I guess we all must be happy, that some developers are doing something at all. (I feel also myself guilty a bit in this regard.)

#100 User is offline   Csantucci 

  • Member, Board of Directors
  • Group: Posts: Elite Member
  • Posts: 7,445
  • Joined: 31-December 11
  • Gender:Male
  • Country:

Posted 05 September 2020 - 12:58 PM

In the code chunk there is in effect an error: in the foreach line the references shouldn't be to TrainInfo, but to LocalTrainInfo.
I also accept your note that this should be computed only once for every loop, and I may try to modify it.
Thanks for the kind "dirty way" expression. As TrainInfo has its main use outside of the TCS management, and as TCS management is often not used, I didn't want to add further computations to get additional data within TrainInfo that aren't used outside of the TCS management.

As you are reviewing the TCS-related code, could you pls comment on this pre-existing line?
                       return list[forsight < list.Count ? forsight : list.Count - 1];

In case forsight is >= list.Count, the last element of the list is returned, instead of signalling that what was asked for isn't available. I don't think this is correct, if I have correctly interpreted the code.

#101 User is offline   gpz 

  • Superintendant
  • Group: Posts: Elite Member
  • Posts: 1,846
  • Joined: 27-October 12
  • Gender:Male
  • Location:Budapest
  • Simulator:OpenRails
  • Country:

Posted 06 September 2020 - 01:10 AM

For the comment in the code, actually the previous line does the job:
if (forsight >= list.Count) SearchTrainInfo(forsight, type);
// <CSComment> Doesn't : list.Count - 1 lead to wrong returns if forsight > 0? </CSComment>
return list[forsight < list.Count ? forsight : list.Count - 1];

The SearchTrainInfo() function extends the list to the requested "forsight". That last line is just a protection, if a too big "forsight" number was asked for, it still returns some value. I didn't want to give back a null value, since the script writer is not expected to always do null-checks on interface functions, it would be a valid expectation from him, that these functions always return something. You may be right, that it was not the best choice to just repeat the last signal (most probably a STOP) to any bigger numbers, there could have been a dummy signal object defined with aspect none, speed limit float.max, etc., and return that one. Yes, this might be a valid change.

In my code I am about to change the TrainInfo object to something like
        Train.TrainInfo TrainInfo {
            get 
            {
                if (!TrainInfoUpdatedFlag) _trainInfo = Locomotive.Train.GetTrainInfo();
                TrainInfoUpdatedFlag = true;
                return _trainInfo;
            }
        }
        Train.TrainInfo _trainInfo = new Train.TrainInfo();
        bool TrainInfoUpdatedFlag;

where the TrainInfoUpdatedFlag = false can be set in the ClearParams() function, so this way the TrainInfo is updated only once per Update() call, but for sure gets updated at the first use.

I am also about to add the collecting of the generic signals and the trailing switches to the TrainInfo. If we want long-term maintainability, or make our successor developers to understand what we've done, that is the correct solution I think. It also makes the code more clear, since the current functions are mainly just copies from the TrainInfo with slightly modified functionality. (Anyway, they are well coded functions, imho.) TrainInfo is there mainly for feeding the MSTS-style track monitor, and e.g. the ETCS track monitor is just a more advanced track monitor. So these additions naturally belong there. In long term the OR track monitor probably should also be updated to have the missing functions that other TCS system track monitors have.

#102 User is offline   gpz 

  • Superintendant
  • Group: Posts: Elite Member
  • Posts: 1,846
  • Joined: 27-October 12
  • Gender:Male
  • Location:Budapest
  • Simulator:OpenRails
  • Country:

Posted 06 September 2020 - 02:57 AM

Just a note about my original code: Probably my original SearchTrainInfo() function is also overcomplicated. I was coded it to build other List()-s of different type of objects based on hits in TrainInfo. But it is absolutely unnecessary. The simplest way is just returning directly the found TrainInfo member's properties, without additional magic... TrainInfo is the master database, that (should) contain all the necessary data. I must add the altitudes there as well...

#103 User is offline   Csantucci 

  • Member, Board of Directors
  • Group: Posts: Elite Member
  • Posts: 7,445
  • Joined: 31-December 11
  • Gender:Male
  • Country:

Posted 10 September 2020 - 01:05 PM

I have introduced some of the suggestions by Peter about TrainInfo into rev. 75 of OR NewYear MG.

#104 User is offline   YoRyan 

  • Conductor
  • Group: Posts: Active Member
  • Posts: 391
  • Joined: 19-February 20
  • Gender:Male
  • Location:California, United States
  • Simulator:Open Rails/unstable
  • Country:

Posted 10 October 2020 - 09:05 AM

So, what's the status on these proposed changes? Are we doing anything to the Locomotive handle? Are we going to upstream the TrainInfo improvements?

#105 User is offline   gpz 

  • Superintendant
  • Group: Posts: Elite Member
  • Posts: 1,846
  • Joined: 27-October 12
  • Gender:Male
  • Location:Budapest
  • Simulator:OpenRails
  • Country:

Posted 12 October 2020 - 01:54 AM

I've finished with 80-90% of the coding, but only 5-10% of the testing... One may take a look on the code here on Github, but it is not worth tying to download it yet, currently it is not even in a compilable state. I am yet to figure out how to query the altitudes of different signalling elements. (I'm sorry, I have less time for coding than it would be ideal.)

The to-be-PR of this code will not contain the removal of the Locomotive handle to allow people to make the transition smooth, but that handle must be removed not later than just before the unstable-testing branch goes stable.

  • 9 Pages +
  • « First
  • 5
  • 6
  • 7
  • 8
  • 9
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users