summaryrefslogtreecommitdiffhomepage
path: root/proto-wine/ftnoir_protocol_wine.cpp
blob: bae02b06b461f57a09592d94db56127ef86bccc5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#include "ftnoir_protocol_wine.h"
#include <qprocess.h>
#ifndef OTR_WINE_NO_WRAPPER
#   include "csv/csv.h"
#endif

#include <cstring>
#include <cmath>

#include <QString>
#include <QDebug>

#include "proton.h"

wine::wine() = default;

wine::~wine()
{
#ifndef OTR_WINE_NO_WRAPPER
    bool exit = false;
    if (shm) {
        shm->stop = true;
        exit = wrapper.waitForFinished(100);
        if (exit)
            qDebug() << "proto/wine: wrapper exit code" << wrapper.exitCode();
    }
    if (!exit)
    {
        if (wrapper.state() != QProcess::NotRunning)
            wrapper.kill();
        wrapper.waitForFinished(1000);
    }
#endif
    //shm_unlink("/" WINE_SHM_NAME);
}

void wine::pose(const double *headpose, const double*)
{
    if (shm)
    {
        lck_shm.lock();
        for (int i = 3; i < 6; i++)
            shm->data[i] = (headpose[i] * M_PI) / 180;
        for (int i = 0; i < 3; i++)
            shm->data[i] = headpose[i] * 10;
#ifndef OTR_WINE_NO_WRAPPER
        if (shm->gameid != gameid)
        {
            //qDebug() << "proto/wine: looking up gameData";
            QString gamename;
            QMutexLocker foo(&game_name_mutex);
            /* only EZCA for FSX requires dummy process, and FSX doesn't work on Linux */
            /* memory-hacks DLL can't be loaded into a Linux process, either */
            CSV::getGameData(shm->gameid, shm->table, gamename);
            gameid = shm->gameid2 = shm->gameid;
            connected_game = gamename;
        }
#endif
        lck_shm.unlock();
    }
}

module_status wine::initialize()
{
#ifndef OTR_WINE_NO_WRAPPER
    static const QString library_path(OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH);

    /////////////////////////
    // determine wine path //
    /////////////////////////
    QString wine_path = "wine";

    if (s.variant_wine) {
        // NORMAL WINE

        // resolve combo box
        if (s.wine_select_path().toString() != "WINE") {
            // if we are not supposed to use system wine then:
            if (s.wine_select_path().toString() != "CUSTOM") {
                // if we don't have a custom path then change the wine_path to the path corresponding to the selected version
                wine_path = s.wine_select_path().toString();
            }
            else if (!s.wine_custom_path->isEmpty()) {
                // if we do have a custom path and it is not empty then
                wine_path = s.wine_custom_path;
            }
        }

        // parse tilde if present
        if (wine_path[0] == '~')
            wine_path = qgetenv("HOME") + wine_path.mid(1);
    }
    else if (s.variant_proton)
    {
        // PROTON

        wine_path = s.proton_path().toString() + "/bin/wine";
    }
    qDebug() << "proto/wine: wine_path:" << wine_path;


    /////////////////////////////////////
    // determine environment variables //
    /////////////////////////////////////
    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();

    // if proton is used setup proton environment
    if (s.variant_proton)
    {
        auto [proton_env, env_error_string, env_success] = make_steam_environ(s.proton_path().toString());
        env = proton_env;

        if (!env_success)
            return error(env_error_string);
    }

    // determine wineprefix
    if (s.variant_proton && s.variant_proton_steamplay) {
        // wine prefix is dependend on steam

        if (s.proton_appid == 0)
            return error(tr("Must specify application id for Proton (Steam Play)"));

        auto [prefix, error_string, success] = make_wineprefix(s.proton_appid);
        qDebug() << "proto/wine: wineprefix:" << prefix;
        env.insert("WINEPREFIX", prefix);

        if (!success)
            return error(error_string);
    }
    else {
        // wine prefix was supplied via path

        QString wineprefix = "";

        // check if prefix was supplied via wine
        if (s.variant_wine && !s.wineprefix->isEmpty())
            wineprefix = s.wineprefix;

        // check if prefix was supplied via proton
        if (s.variant_proton_external && !s.protonprefix->isEmpty())
            wineprefix = s.protonprefix;

        // check if the user specified a prefix anywhere
        if (wineprefix.isEmpty())
            return error(tr("Prefix has not been defined!").arg(wineprefix));

        // handle tilde
        if (wineprefix[0] == '~')
            wineprefix = qgetenv("HOME") + wineprefix.mid(1);

        // return error if relative path is given
        if (wineprefix[0] != '/')
            return error(tr("Wine prefix must be an absolute path (given '%1')").arg(wineprefix));

        qDebug() << "proto/wine: wineprefix:" << wineprefix;

        env.insert("WINEPREFIX", wineprefix);
    }

    // ESYNC and FSYNC
    if (s.esync)
        env.insert("WINEESYNC", "1");
    if (s.fsync)
        env.insert("WINEFSYNC", "1");

    // Headtracking Protocol
    env.insert("OTR_WINE_PROTO", QString::number(s.protocol+1));


    ////////////////////////////////
    // launch the wrapper program //
    ////////////////////////////////

    wrapper.setProcessEnvironment(env);
    wrapper.setWorkingDirectory(OPENTRACK_BASE_PATH);
    wrapper.start(wine_path, { library_path + "opentrack-wrapper-wine.exe.so" });
    wrapper.waitForStarted();
    if (wrapper.state() == QProcess::ProcessState::NotRunning) {
        return error(tr("Failed to start Wine! Make sure the binary is set correctly."));
    }
#endif

    if (lck_shm.success())
    {
        shm = (WineSHM*) lck_shm.ptr();
        memset(shm, 0, sizeof(*shm));

        qDebug() << "proto/wine: shm success";

        // display "waiting for game message" (overwritten once a game is detected)
#ifndef OTR_WINE_NO_WRAPPER
        connected_game = "waiting for game...";
#endif
    }
    else {
        qDebug() << "proto/wine: shm no success";
    }

    if (lck_shm.success())
        return status_ok();
    else
        return error(tr("Can't open shared memory mapping"));
}

OPENTRACK_DECLARE_PROTOCOL(wine, FTControls, wine_metadata)