C++ Question Write to file syntax help [solved]

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
1,924
Reaction score
340
Points
98
Location
Sparta
Hey everyone, I am having some difficulty figuring out the syntax for the following task.

I have an eva vessel, which I am deleting when it's close to a docking port and a key is pressed. Then I shift the focus to the vessel.

The code is this and it works ok so far.

C++:
void GVmmu::EndEVA()
{
    VECTOR3 gpos, mepos, pos, dir, rot;
    GetGlobalPos(mepos);
    OBJHANDLE eva;

    for (DWORD i = 0; i < oapiGetVesselCount(); i++)
    {
        OBJHANDLE hV = oapiGetVesselByIndex(i);
        if (hV == GetHandle()) continue; // we don't want to grapple ourselves ...
        oapiGetGlobalPos(hV, &gpos);
        if (dist(gpos, mepos) < oapiGetSize(hV))
        {
            VESSEL *v = oapiGetVesselInterface(hV);
            DWORD nDock = v->DockCount();
            if (nDock == 0) continue;
            for (DWORD j = 0; j < nDock; j++)
            {
                DOCKHANDLE hDock = v->GetDockHandle(j);
                v->GetDockParams(hDock, pos, dir, rot);
                v->Local2Global(pos, gpos);
                if (abs(dist(gpos, mepos)) < 3) {
                    eva = GetHandle();
                    oapiDeleteVessel(eva);
                    oapiSetFocusObject(hV);
                }
            }
        }
    }
}

Before the eva gets deleted, I want to do the following:
Get the dock's vessel name (let's call it shipname) and open a file in Config\(mydirectory)\shipname.cfg

If the file exists, look for the first line that is empty and write there the name of the eva.

If the file doesn't exist, create it and write the name of the eva on the first line.

if the file exists but there is no empty line, write the name at the end.

Example of contents of existing file in Config\(mydirectory)\XR2-01.cfg

Code:
Lee_Nash
Kara_Miller

In the example above, the name of the eva, should be placed on line 3, because it's the first empty line.

I don't know my way around c++ , so the syntax to achieve this eludes me. Any help is much appreciated.
 

BrianJ

Addon Developer
Addon Developer
Joined
Apr 19, 2008
Messages
1,676
Reaction score
900
Points
128
Location
Code 347
Hi,
there are some functions in OrbiterAPI that might be of help, e.g. oapiOpenFile, oapiCloseFile, oapiWriteLine.
I haven't tried the following code, but it might work...?

Code:
void GVmmu::EndEVA()
{
VECTOR3 gpos, mepos, pos, dir, rot;
GetGlobalPos(mepos);
OBJHANDLE eva;

for (DWORD i = 0; i < oapiGetVesselCount(); i++)
{
OBJHANDLE hV = oapiGetVesselByIndex(i);
if (hV == GetHandle()) continue; // we don't want to grapple ourselves ...
oapiGetGlobalPos(hV, &gpos);
if (dist(gpos, mepos) < oapiGetSize(hV))
{
VESSEL *v = oapiGetVesselInterface(hV);
DWORD nDock = v->DockCount();
if (nDock == 0) continue;
for (DWORD j = 0; j < nDock; j++)
{
DOCKHANDLE hDock = v->GetDockHandle(j);
v->GetDockParams(hDock, pos, dir, rot);
v->Local2Global(pos, gpos);
if (abs(dist(gpos, mepos)) < 3) {

///////////////////////////////////// BrianJ stuff //////////////////////////////

 char evaname[256];
 oapiGetObjectName(GetHandle(), evaname, 256);

char shipname[256];
oapiGetObjectName(hV, shipname, 256);

 char filename[256];
 strcpy(filename, "mydirectory/");
 strcat(filename, shipname);
 strcat(filename, ".cfg")

    FILEHANDLE hFile = oapiOpenFile(filename, FILE_APP, CONFIG);
            if (!hFile)
            {
            hFile = oapiOpenFile(filename, FILE_OUT, CONFIG);
            oapiWriteLine(hFile, evaname);
            oapiCloseFile(hFile, FILE_OUT);
            }       

            else
            {
            oapiWriteLine(hFile, evaname);
            oapiCloseFile(hFile, FILE_APP);
            }

/////////////////////////////////////////////////////////////////////////////////

eva = GetHandle();
oapiDeleteVessel(eva);
oapiSetFocusObject(hV);
}
}
}
}
}
 

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
1,924
Reaction score
340
Points
98
Location
Sparta
Thank you so much Brian!

Works perfectly! One additional question though: If the file exists, it might be in this format:

Lee_Nash
Kara_Miller

William_Adama
How can I insert the evaname at the first empty line, instead of the end?
(So the file becomes):
Lee_Nash
Kara_Miller
evaname
William_Adama
 

BrianJ

Addon Developer
Addon Developer
Joined
Apr 19, 2008
Messages
1,676
Reaction score
900
Points
128
Location
Code 347
You're very welcome :)
How can I insert the evaname at the first empty line, instead of the end?
I don't know! Are you sure it doesn't happen that way anyway? (he asked hopefully).
I'll have a think, but I'm sure one of the code wizards here will know how......
 

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
1,924
Reaction score
340
Points
98
Location
Sparta
Are you sure it doesn't happen that way anyway? (he asked hopefully).
Yes, I tested it with the example above and the evaname gets written at the end of the file. I think I might have to replace all the lines with new ones, to include the change.
I was just reading this: Replace a line in a text file

C++:
#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    string strReplace = "HELLO";
    string strNew = "GOODBYE";
    ifstream filein("filein.txt"); //File to read from
    ofstream fileout("fileout.txt"); //Temporary file
    if(!filein || !fileout)
    {
        cout << "Error opening files!" << endl;
        return 1;
    }

    string strTemp;
    //bool found = false;
    while(filein >> strTemp)
    {
        if(strTemp == strReplace){
            strTemp = strNew;
            //found = true;
        }
        strTemp += "\n";
        fileout << strTemp;
        //if(found) break;
    }
    return 0;
}

I'll try to implement it and see if it works.

Thank you again for your time and input.
 

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
1,924
Reaction score
340
Points
98
Location
Sparta
Ok, there has to be a better way to do this.

I've ended up using a temporary file and a special character instead of an empty line to kinda do what I want.
C++:
                    string strReplace = "@";
                    string strNew = GetName();
                    ifstream filein(filename); //File to read from
                    ofstream fileout(filename_temp); //Temporary file
                    string strTemp;
                    bool found = false;
                    while (filein >> strTemp)
                    {
                        if (strTemp == strReplace) {
                            strTemp = strNew;
                            found = true;
                        }
                        strTemp += "\n";
                        fileout << strTemp;
                        //if(found) break;
                    }
This is the existiing cfg file:
Chrisjen_Avasarala
@
Buzz_Aldrin
@
Deanna_Troi
Dr_Amelia_Brand
Ellen_Ripley
Geordi_La_Forge
Han_Solo
Inara_Serra
Jadzia_Dax
James_Holden
James_Kirk
Jean_Luc_Picard
After running the eva code (evaname = Bob_Behnken) it turns into this:
Chrisjen_Avasarala
Bob_Behnken
Buzz_Aldrin
Bob_Behnken
Deanna_Troi
Dr_Amelia_Brand
Ellen_Ripley
Geordi_La_Forge
Han_Solo
Inara_Serra
Jadzia_Dax
James_Holden
James_Kirk
Jean_Luc_Picard
As you can see both "@" characters were replaced with the evaname. The problem is that I want to change only the first one. So it should be like this:
Chrisjen_Avasarala
Bob_Behnken
Buzz_Aldrin
@
Deanna_Troi
Dr_Amelia_Brand
Ellen_Ripley
Geordi_La_Forge
Han_Solo
Inara_Serra
Jadzia_Dax
James_Holden
James_Kirk
Jean_Luc_Picard

Does anyone have any pointers to give me?
 

Thymo

I like breaking things
Addon Developer
Joined
Jun 26, 2016
Messages
120
Reaction score
148
Points
58
Website
nassp.space
What endgoal are you working towards? We would be able to give you better advice if we know what you want to achieve with these config files.
 

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
1,924
Reaction score
340
Points
98
Location
Sparta
What endgoal are you working towards? We would be able to give you better advice if we know what you want to achieve with these config files.
The config files are used to keep track of the crew on board a vessel. Everytime an mmu enters a docking port, the name needs to be added to the ship's cfg. Furthermore, I also want to keep track of the position, because on some ships, the stored name and its position in the file are used to load meshes and insert them in their correct position. I also want to keep some seats empty if I want to, hence the need to keep some inbetween lines empty in the cfg files.
 

BrianJ

Addon Developer
Addon Developer
Joined
Apr 19, 2008
Messages
1,676
Reaction score
900
Points
128
Location
Code 347
Hi,
I haven't got a solution to your "empty line" problem, but I did have a couple of thoughts about how I would tackle this, going a slightly different route.
1. I would store info about current crew in the scenario.
You could have a "default" crew listed in the .cfg as well, but scenario entry would take priority.
2. I would give each crew member "place" a numerical tag, so you can run through a list by number and check if crew member exists, check crew status (if required), associate a position for the crew mesh to the tag, etc.etc.
So your .cfg might look like this:
Code:
CREW0 Chrisjen_Avasarala
CREW1 Bob_Behnken
CREW2 Buzz_Aldrin
CREW4 Deanna_Troi
(Crew3 seat is empty)

and in the .scn you might add a status indicator (0 = Onboard, 1 = EVA)
Code:
CREW0 Chrisjen_Avasarala 0
CREW1 Bob_Behnken 1
CREW2 Buzz_Aldrin 0
CREW4 Deanna_Troi 0

Of course, I don't know what other functionality you need to build-in, so these ideas may not be appropriate.
You will also need some kind of method for "telling" your vessel that an EVA crew has come aboard, but that's another issue.
Good luck!
Brian
 

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
1,924
Reaction score
340
Points
98
Location
Sparta
Hi,
I haven't got a solution to your "empty line" problem, but I did have a couple of thoughts about how I would tackle this, going a slightly different route.
1. I would store info about current crew in the scenario.
You could have a "default" crew listed in the .cfg as well, but scenario entry would take priority.
2. I would give each crew member "place" a numerical tag, so you can run through a list by number and check if crew member exists, check crew status (if required), associate a position for the crew mesh to the tag, etc.etc.
So your .cfg might look like this:
Code:
CREW0 Chrisjen_Avasarala
CREW1 Bob_Behnken
CREW2 Buzz_Aldrin
CREW4 Deanna_Troi
(Crew3 seat is empty)

and in the .scn you might add a status indicator (0 = Onboard, 1 = EVA)
Code:
CREW0 Chrisjen_Avasarala 0
CREW1 Bob_Behnken 1
CREW2 Buzz_Aldrin 0
CREW4 Deanna_Troi 0

Of course, I don't know what other functionality you need to build-in, so these ideas may not be appropriate.
You will also need some kind of method for "telling" your vessel that an EVA crew has come aboard, but that's another issue.
Good luck!
Brian
Thank you very much for your time and input Brian. The solution you propose seems more robust and might be more helpful down the line.

I think I've solved the original problem for now, by using a special character in each empty line and converting the whole file to a string. Then I use a string.replace to change the special character to the name of the eva mmu and finally write the string back to the file.

I am currently testing this to see if it works properly, but I'll definitely see if I can implement the method you propose, since it seems more versatile and robust than what I'm doing now.

Thanks again for all your help!
 

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
1,924
Reaction score
340
Points
98
Location
Sparta
For anyone interested, this is what I ended up implementing. I changed the empty lines in the file that I wanted to edit to 'no_crew' and then I used this:

C++:
void GVmmu::EndEVA()
{
    VECTOR3 gpos, mepos, pos, dir, rot;
    GetGlobalPos(mepos);
    OBJHANDLE eva;

    for (DWORD i = 0; i < oapiGetVesselCount(); i++)
    {
        OBJHANDLE hV = oapiGetVesselByIndex(i);
        if (hV == GetHandle()) continue; // we don't want to grapple ourselves ...
        oapiGetGlobalPos(hV, &gpos);
        if (dist(gpos, mepos) < 50) // get the vessels within 50 meters
        {
            VESSEL *v = oapiGetVesselInterface(hV);
            DWORD nDock = v->DockCount();
            if (nDock == 0) continue;
            for (DWORD j = 0; j < nDock; j++)
            {
                DOCKHANDLE hDock = v->GetDockHandle(j);
                v->GetDockParams(hDock, pos, dir, rot);
                v->Local2Global(pos, gpos); //get the distances to all docks within 50 meters
                if (abs(dist(gpos, mepos)) < 3) {    //if the distance to the closest dock is less than 3 meters

                    char evaname[256];  
                    char shipname[256];
                    string classname = { v->GetClassNameA() };
                    char filename[256];
                    oapiGetObjectName(GetHandle(), evaname, 256);
                    oapiGetObjectName(hV, shipname, 256);
                    strcpy(filename, "./Config/CrewMFD/");
                    strcat(filename, shipname);
                    strcat(filename, ".cfg");
                    ifstream filein(filename);
                    
                    if (!filein) {  //if the file doesn't exist
                        if (classname != "XR2Ravenstar") { //if the dock doesn't belong to a Ravenstar
                            FILEHANDLE hFile = oapiOpenFile(filename, FILE_OUT, ROOT);
                            oapiWriteLine(hFile, evaname);
                            for (UINT i = 0; i < 13; i++) {
                                oapiWriteLine(hFile, "no_crew");
                            }
                            oapiCloseFile(hFile, FILE_OUT);
                        }
                        if (classname == "XR2Ravenstar") {//if the dock belongs to a Ravenstar 
                            FILEHANDLE hFile = oapiOpenFile(filename, FILE_OUT, ROOT);
                            oapiWriteLine(hFile, "Lee_Nash");
                            oapiWriteLine(hFile, "Kara_Miller");
                            oapiWriteLine(hFile, evaname);
                            for (UINT i = 0; i < 11; i++) {
                                oapiWriteLine(hFile, "no_crew");
                            }
                            oapiCloseFile(hFile, FILE_OUT);
                        }
                    } 
                   // if the file exists
                    string strTemp;
                    string strReplace = "no_crew";
                    string strNew = GetName();
                    ostringstream ss;
                    ss << filein.rdbuf(); // read the file
                    strTemp = ss.str(); // conver to string
                    size_t found = strTemp.find(strReplace); //check if no_crew entry exists
                    if (found != string::npos) { strTemp.replace(strTemp.find(strReplace), strReplace.length(), strNew); //if it doesn't exist, write the evaname at the end
                    ofstream fileout(filename);
                    fileout << strTemp;  //write to the file
                    }
                   
                    eva = GetHandle();
                    oapiDeleteVessel(eva);
                    oapiSetFocusObject(hV);
                }
            }
        }
    }
}

It behaves exactly as I wanted to, but I did have to change the empty lines in my file to ones that say 'no_crew'

Big thanks to BrianJ for the valuable input!
 
Top