CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/Dialog/PSPNetconfDialog.cpp
Views: 1401
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include <algorithm>
19
#include "Common/CommonWindows.h"
20
#include "Common/TimeUtil.h"
21
#include "Common/Data/Text/I18n.h"
22
#include "Common/Serialize/Serializer.h"
23
#include "Common/Serialize/SerializeFuncs.h"
24
#include "Core/Config.h"
25
#include "Core/MemMapHelpers.h"
26
#include "Core/Util/PPGeDraw.h"
27
#include "Core/HLE/sceKernelMemory.h"
28
#include "Core/HLE/sceCtrl.h"
29
#include "Core/HLE/sceUtility.h"
30
#include "Core/HLE/sceNet.h"
31
#include "Core/HLE/sceNetAdhoc.h"
32
#include "Core/Dialog/PSPNetconfDialog.h"
33
#include "Common/Data/Encoding/Utf8.h"
34
35
36
#define NETCONF_CONNECT_APNET 0
37
#define NETCONF_STATUS_APNET 1
38
#define NETCONF_CONNECT_ADHOC 2
39
#define NETCONF_CONNECT_APNET_LAST 3
40
#define NETCONF_CREATE_ADHOC 4
41
#define NETCONF_JOIN_ADHOC 5
42
43
static const float FONT_SCALE = 0.65f;
44
45
// Needs testing.
46
const static int NET_INIT_DELAY_US = 200000;
47
const static int NET_SHUTDOWN_DELAY_US = 200000;
48
const static int NET_CONNECT_TIMEOUT = 15000000; // Using 15 secs to match the timeout on Adhoc Server side (SERVER_USER_TIMEOUT)
49
50
struct ScanInfos {
51
s32_le sz;
52
SceNetAdhocctlScanInfoEmu si;
53
} PACK;
54
55
56
PSPNetconfDialog::PSPNetconfDialog(UtilityDialogType type) : PSPDialog(type) {
57
}
58
59
PSPNetconfDialog::~PSPNetconfDialog() {
60
}
61
62
int PSPNetconfDialog::Init(u32 paramAddr) {
63
// Already running
64
if (ReadStatus() != SCE_UTILITY_STATUS_NONE)
65
return SCE_ERROR_UTILITY_INVALID_STATUS;
66
67
requestAddr = paramAddr;
68
int size = Memory::Read_U32(paramAddr);
69
memset(&request, 0, sizeof(request));
70
// Only copy the right size to support different request format
71
Memory::Memcpy(&request, paramAddr, size);
72
73
ChangeStatusInit(NET_INIT_DELAY_US);
74
75
// Eat any keys pressed before the dialog inited.
76
InitCommon();
77
UpdateButtons();
78
79
connResult = -1;
80
scanInfosAddr = 0;
81
scanStep = 0;
82
startTime = (u64)(time_now_d() * 1000000.0);
83
84
StartFade(true);
85
return 0;
86
}
87
88
void PSPNetconfDialog::DrawBanner() {
89
90
PPGeDrawRect(0, 0, 480, 22, CalcFadedColor(0x65636358));
91
92
PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_VCENTER, 0.6f);
93
textStyle.hasShadow = false;
94
95
// TODO: Draw a hexagon icon
96
PPGeDrawImage(10, 5, 11.0f, 10.0f, 1, 10, 1, 10, 10, 10, FadedImageStyle());
97
auto di = GetI18NCategory(I18NCat::DIALOG);
98
PPGeDrawText(di->T("Network Connection"), 31, 10, textStyle);
99
}
100
101
void PSPNetconfDialog::DrawIndicator() {
102
// TODO: Draw animated circle as processing indicator
103
PPGeDrawImage(456, 248, 20.0f, 20.0f, 1, 10, 1, 10, 10, 10, FadedImageStyle());
104
}
105
106
void PSPNetconfDialog::DisplayMessage(std::string_view text1, std::string_view text2a, std::string_view text2b, std::string_view text3a, std::string_view text3b, bool hasYesNo, bool hasOK) {
107
auto di = GetI18NCategory(I18NCat::DIALOG);
108
109
PPGeStyle buttonStyle = FadedStyle(PPGeAlign::BOX_CENTER, FONT_SCALE);
110
PPGeStyle messageStyle = FadedStyle(PPGeAlign::BOX_HCENTER, FONT_SCALE);
111
PPGeStyle messageStyleRight = FadedStyle(PPGeAlign::BOX_RIGHT, FONT_SCALE);
112
PPGeStyle messageStyleLeft = FadedStyle(PPGeAlign::BOX_LEFT, FONT_SCALE);
113
114
std::string text2 = std::string(text2a) + " " + std::string(text2b);
115
std::string text3 = std::string(text3a) + " " + std::string(text3b);
116
117
// Without the scrollbar, we have 350 total pixels.
118
float WRAP_WIDTH = 300.0f;
119
if (UTF8StringNonASCIICount(text1) >= (int)text1.size() / 4) {
120
WRAP_WIDTH = 336.0f;
121
if (text1.size() > 12) {
122
messageStyle.scale = 0.6f;
123
}
124
}
125
126
float totalHeight1 = 0.0f;
127
PPGeMeasureText(nullptr, &totalHeight1, text1, FONT_SCALE, PPGE_LINE_WRAP_WORD, WRAP_WIDTH);
128
float totalHeight2 = 0.0f;
129
if (text2 != " ")
130
PPGeMeasureText(nullptr, &totalHeight2, text2, FONT_SCALE, PPGE_LINE_USE_ELLIPSIS, WRAP_WIDTH);
131
float totalHeight3 = 0.0f;
132
if (text3 != " ")
133
PPGeMeasureText(nullptr, &totalHeight3, text3, FONT_SCALE, PPGE_LINE_USE_ELLIPSIS, WRAP_WIDTH);
134
float marginTop = 0.0f;
135
if (text2 != " " || text3 != " ")
136
marginTop = 11.0f;
137
float totalHeight = totalHeight1 + totalHeight2 + totalHeight3 + marginTop;
138
// The PSP normally only shows about 8 lines at a time.
139
// For improved UX, we intentionally show part of the next line.
140
float visibleHeight = std::min(totalHeight, 175.0f);
141
float h2 = visibleHeight / 2.0f;
142
143
float centerY = 135.0f;
144
float sy = centerY - h2 - 15.0f;
145
float ey = centerY + h2 + 20.0f;
146
float buttonY = centerY + h2 + 5.0f;
147
148
auto drawSelectionBoxAndAdjust = [&](float x) {
149
// Box has a fixed size.
150
float w = 15.0f;
151
float h = 8.0f;
152
PPGeDrawRect(x - w, buttonY - h, x + w, buttonY + h, CalcFadedColor(0x6DCFCFCF));
153
154
centerY -= h + 5.0f;
155
sy -= h + 5.0f;
156
ey = buttonY + h * 2.0f + 5.0f;
157
};
158
159
if (hasYesNo) {
160
if (yesnoChoice == 1) {
161
drawSelectionBoxAndAdjust(204.0f);
162
}
163
else {
164
drawSelectionBoxAndAdjust(273.0f);
165
}
166
167
PPGeDrawText(di->T("Yes"), 203.0f, buttonY - 1.0f, buttonStyle);
168
PPGeDrawText(di->T("No"), 272.0f, buttonY - 1.0f, buttonStyle);
169
if (IsButtonPressed(CTRL_LEFT) && yesnoChoice == 0) {
170
yesnoChoice = 1;
171
}
172
else if (IsButtonPressed(CTRL_RIGHT) && yesnoChoice == 1) {
173
yesnoChoice = 0;
174
}
175
buttonY += 8.0f + 5.0f;
176
}
177
178
if (hasOK) {
179
drawSelectionBoxAndAdjust(240.0f);
180
181
PPGeDrawText(di->T("OK"), 239.0f, buttonY - 1.0f, buttonStyle);
182
buttonY += 8.0f + 5.0f;
183
}
184
185
PPGeScissor(0, (int)(centerY - h2 - 2), 480, (int)(centerY + h2 + 2));
186
PPGeDrawTextWrapped(text1, 240.0f, centerY - h2 - scrollPos_, WRAP_WIDTH, 0, messageStyle);
187
if (!text2a.empty()) {
188
if (!text2b.empty())
189
PPGeDrawTextWrapped(text2a, 240.0f - 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + marginTop, WRAP_WIDTH, 0, messageStyleRight);
190
else
191
PPGeDrawTextWrapped(text2a, 240.0f, centerY - h2 - scrollPos_ + totalHeight1 + marginTop, WRAP_WIDTH, 0, messageStyle);
192
}
193
if (!text2b.empty())
194
PPGeDrawTextWrapped(text2b, 240.0f + 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + marginTop, WRAP_WIDTH, 0, messageStyleLeft);
195
if (!text3a.empty()) {
196
if (!text3b.empty())
197
PPGeDrawTextWrapped(text3a, 240.0f - 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + totalHeight2 + marginTop, WRAP_WIDTH, 0, messageStyleRight);
198
else
199
PPGeDrawTextWrapped(text3a, 240.0f, centerY - h2 - scrollPos_ + totalHeight1 + totalHeight2 + marginTop, WRAP_WIDTH, 0, messageStyle);
200
}
201
if (!text3b.empty())
202
PPGeDrawTextWrapped(text3b, 240.0f + 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + totalHeight2 + marginTop, WRAP_WIDTH, 0, messageStyleLeft);
203
PPGeScissorReset();
204
205
// Do we need a scrollbar?
206
if (visibleHeight < totalHeight) {
207
float scrollSpeed = 5.0f;
208
float scrollMax = totalHeight - visibleHeight;
209
210
float bobHeight = (visibleHeight / totalHeight) * visibleHeight;
211
float bobOffset = (scrollPos_ / scrollMax) * (visibleHeight - bobHeight);
212
float bobY1 = centerY - h2 + bobOffset;
213
PPGeDrawRect(415.0f, bobY1, 420.0f, bobY1 + bobHeight, CalcFadedColor(0xFFCCCCCC));
214
215
auto buttonDown = [this](int btn, int& held) {
216
if (IsButtonPressed(btn)) {
217
held = 0;
218
return true;
219
}
220
return IsButtonHeld(btn, held, 1, 1);
221
};
222
if (buttonDown(CTRL_DOWN, framesDownHeld_) && scrollPos_ < scrollMax) {
223
scrollPos_ = std::min(scrollMax, scrollPos_ + scrollSpeed);
224
}
225
if (buttonDown(CTRL_UP, framesUpHeld_) && scrollPos_ > 0.0f) {
226
scrollPos_ = std::max(0.0f, scrollPos_ - scrollSpeed);
227
}
228
}
229
230
PPGeDrawRect(60.0f, sy, 420.0f, sy + 1.0f, CalcFadedColor(0xFFFFFFFF));
231
PPGeDrawRect(60.0f, ey, 420.0f, ey + 1.0f, CalcFadedColor(0xFFFFFFFF));
232
}
233
234
int PSPNetconfDialog::Update(int animSpeed) {
235
if (ReadStatus() != SCE_UTILITY_STATUS_RUNNING) {
236
return SCE_ERROR_UTILITY_INVALID_STATUS;
237
}
238
239
UpdateButtons();
240
UpdateCommon();
241
auto di = GetI18NCategory(I18NCat::DIALOG);
242
u64 now = (u64)(time_now_d() * 1000000.0);
243
244
// It seems JPCSP doesn't check for NETCONF_STATUS_APNET
245
if (request.netAction == NETCONF_CONNECT_APNET || request.netAction == NETCONF_STATUS_APNET || request.netAction == NETCONF_CONNECT_APNET_LAST) {
246
int state = NetApctl_GetState();
247
248
UpdateFade(animSpeed);
249
StartDraw();
250
251
if (!hideNotice) {
252
auto err = GetI18NCategory(I18NCat::ERRORS);
253
const float WRAP_WIDTH = 254.0f;
254
const int confirmBtn = GetConfirmButton();
255
const int cancelBtn = GetCancelButton();
256
const ImageID confirmBtnImage = confirmBtn == CTRL_CROSS ? ImageID("I_CROSS") : ImageID("I_CIRCLE");
257
const ImageID cancelBtnImage = cancelBtn == CTRL_CIRCLE ? ImageID("I_CIRCLE") : ImageID("I_CROSS");
258
259
PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_CENTER, 0.5f);
260
PPGeStyle buttonStyle = FadedStyle(PPGeAlign::BOX_LEFT, 0.5f);
261
262
PPGeDrawRect(0, 0, 480, 272, CalcFadedColor(0x63636363));
263
DrawBanner();
264
PPGeDrawTextWrapped(err->T("PPSSPPDoesNotSupportInternet", "PPSSPP currently does not support connecting to the Internet for DLC, PSN, or game updates.\nContinuing may cause unexpected behavior or freezes."), 241, 132, WRAP_WIDTH, 0, textStyle);
265
PPGeDrawImage(confirmBtnImage, 185, 240, 20, 20, buttonStyle);
266
PPGeDrawText(di->T("OK"), 215, 243, buttonStyle);
267
PPGeDrawImage(cancelBtnImage, 255, 240, 20, 20, buttonStyle);
268
PPGeDrawText(di->T("Cancel"), 285, 243, buttonStyle);
269
270
// Since we don't support Infrastructure API yet.. Let the Player read the message first and choose to continue or not (ie. for testing networks API)
271
if (IsButtonPressed(cancelBtn)) {
272
StartFade(false);
273
ChangeStatus(SCE_UTILITY_STATUS_FINISHED, NET_SHUTDOWN_DELAY_US);
274
// TODO: When the dialog is aborted, does it really set the result to this?
275
// It seems to make Phantasy Star Portable 2 happy, so it should be okay for now.
276
request.common.result = SCE_UTILITY_DIALOG_RESULT_ABORT;
277
}
278
else if (IsButtonPressed(confirmBtn)) {
279
hideNotice = true;
280
StartFade(true);
281
}
282
}
283
else {
284
PPGeDrawRect(0, 0, 480, 272, CalcFadedColor(0xC0C8B2AC));
285
DrawBanner();
286
DrawIndicator();
287
288
if (state == PSP_NET_APCTL_STATE_GOT_IP || state == PSP_NET_APCTL_STATE_GETTING_IP) {
289
DisplayMessage(di->T("ObtainingIP", "Obtaining IP address.\nPlease wait..."), di->T("ConnectionName", "Connection Name"), netApctlInfo.name, di->T("SSID"), netApctlInfo.ssid);
290
}
291
else {
292
// Skipping the Select Connection screen since we only have 1 fake profile
293
DisplayMessage(di->T("ConnectingAP", "Connecting to the access point.\nPlease wait..."), di->T("ConnectionName", "Connection Name"), netApctlInfo.name, di->T("SSID"), netApctlInfo.ssid);
294
}
295
DisplayButtons(DS_BUTTON_CANCEL, di->T("Cancel"));
296
297
// The Netconf dialog stays visible until the network reaches the state PSP_NET_APCTL_STATE_GOT_IP.
298
if (state == PSP_NET_APCTL_STATE_GOT_IP) {
299
if (pendingStatus != SCE_UTILITY_STATUS_FINISHED) {
300
StartFade(false);
301
ChangeStatus(SCE_UTILITY_STATUS_FINISHED, NET_SHUTDOWN_DELAY_US);
302
}
303
}
304
305
else if (state == PSP_NET_APCTL_STATE_JOINING) {
306
// Switch to the next message
307
StartFade(true);
308
}
309
310
else if (state == PSP_NET_APCTL_STATE_DISCONNECTED) {
311
// When connecting with infrastructure, simulate a connection using the first network configuration entry.
312
if (connResult < 0) {
313
connResult = sceNetApctlConnect(1);
314
}
315
}
316
}
317
318
EndDraw();
319
}
320
else if (request.netAction == NETCONF_CONNECT_ADHOC || request.netAction == NETCONF_CREATE_ADHOC || request.netAction == NETCONF_JOIN_ADHOC) {
321
int state = NetAdhocctl_GetState();
322
bool timedout = (state == ADHOCCTL_STATE_DISCONNECTED && now - startTime > NET_CONNECT_TIMEOUT);
323
324
UpdateFade(animSpeed);
325
StartDraw();
326
PPGeDrawRect(0, 0, 480, 272, CalcFadedColor(0xC0C8B2AC));
327
DrawBanner();
328
DrawIndicator();
329
330
if (timedout) {
331
// FIXME: Do we need to show error message?
332
std::string message(di->T("InternalError", "An internal error has occurred."));
333
DisplayMessage(message + StringFromFormat("\n(%08X)", connResult));
334
DisplayButtons(DS_BUTTON_CANCEL, di->T("Back"));
335
}
336
else {
337
std::string channel = std::to_string(g_Config.iWlanAdhocChannel);
338
if (g_Config.iWlanAdhocChannel == PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC)
339
channel = "Automatic";
340
341
DisplayMessage(di->T("ConnectingPleaseWait", "Connecting.\nPlease wait..."), std::string(di->T("Channel:")) + std::string(" ") + std::string(di->T(channel)));
342
343
// Only Join mode is showing Cancel button on KHBBS and the button will fade out before the dialog is fading out, probably because it's already connected thus can't be canceled anymore
344
if (request.netAction == NETCONF_JOIN_ADHOC)
345
DisplayButtons(DS_BUTTON_CANCEL, di->T("Cancel"));
346
347
// KHBBS will first enter the arena using NETCONF_CONNECT_ADHOC (auto-create group when not exist yet?), but when the event started the event's creator use NETCONF_CREATE_ADHOC while the joining players use NETCONF_JOIN_ADHOC
348
if (request.NetconfData.IsValid()) {
349
if (state == ADHOCCTL_STATE_DISCONNECTED) {
350
switch (request.netAction)
351
{
352
case NETCONF_CREATE_ADHOC:
353
if (connResult < 0) {
354
connResult = sceNetAdhocctlCreate(request.NetconfData->groupName);
355
}
356
break;
357
case NETCONF_JOIN_ADHOC:
358
// FIXME: Should we Scan for a matching group first before Joining a Group (like adhoc games normally do)? Or Is it really allowed to join non-existing group?
359
if (scanStep == 0) {
360
if (sceNetAdhocctlScan() >= 0) {
361
u32 structsz = sizeof(ScanInfos);
362
if (Memory::IsValidAddress(scanInfosAddr))
363
userMemory.Free(scanInfosAddr);
364
scanInfosAddr = userMemory.Alloc(structsz, false, "NetconfScanInfo");
365
Memory::Write_U32(sizeof(SceNetAdhocctlScanInfoEmu), scanInfosAddr);
366
scanStep = 1;
367
}
368
}
369
else if (scanStep == 1) {
370
s32 sz = Memory::Read_U32(scanInfosAddr);
371
// Get required buffer size
372
if (sceNetAdhocctlGetScanInfo(scanInfosAddr, 0) >= 0) {
373
s32 reqsz = Memory::Read_U32(scanInfosAddr);
374
if (reqsz > sz) {
375
sz = reqsz;
376
if (Memory::IsValidAddress(scanInfosAddr))
377
userMemory.Free(scanInfosAddr);
378
u32 structsz = sz + sizeof(s32);
379
scanInfosAddr = userMemory.Alloc(structsz, false, "NetconfScanInfo");
380
Memory::Write_U32(sz, scanInfosAddr);
381
}
382
if (reqsz > 0) {
383
if (sceNetAdhocctlGetScanInfo(scanInfosAddr, scanInfosAddr + sizeof(s32)) >= 0) {
384
ScanInfos* scanInfos = (ScanInfos*)Memory::GetPointer(scanInfosAddr);
385
int n = scanInfos->sz / sizeof(SceNetAdhocctlScanInfoEmu);
386
// Assuming returned SceNetAdhocctlScanInfoEmu(s) are contagious where next is pointing to current addr + sizeof(SceNetAdhocctlScanInfoEmu)
387
while (n > 0) {
388
SceNetAdhocctlScanInfoEmu* si = (SceNetAdhocctlScanInfoEmu*)Memory::GetPointer(scanInfosAddr + sizeof(s32) + sizeof(SceNetAdhocctlScanInfoEmu) * (n - 1LL));
389
if (memcmp(si->group_name.data, request.NetconfData->groupName, ADHOCCTL_GROUPNAME_LEN) == 0) {
390
// Moving found group info to the front so we can use it on sceNetAdhocctlJoin easily
391
memcpy((char*)scanInfos + sizeof(s32), si, sizeof(SceNetAdhocctlScanInfoEmu));
392
scanStep = 2;
393
break;
394
}
395
n--;
396
}
397
// Target group not found, try to scan again later
398
if (n <= 0) {
399
scanStep = 0;
400
}
401
}
402
}
403
// No group found, try to scan again later
404
else {
405
scanStep = 0;
406
}
407
}
408
}
409
else if (scanStep == 2) {
410
if (connResult < 0) {
411
connResult = sceNetAdhocctlJoin(scanInfosAddr + sizeof(s32));
412
if (connResult >= 0) {
413
// We are done!
414
if (Memory::IsValidAddress(scanInfosAddr))
415
userMemory.Free(scanInfosAddr);
416
scanInfosAddr = 0;
417
}
418
}
419
}
420
break;
421
default:
422
if (connResult < 0) {
423
connResult = sceNetAdhocctlConnect(request.NetconfData->groupName);
424
}
425
break;
426
}
427
}
428
}
429
}
430
431
// The Netconf dialog stays visible until the network reaches the state ADHOCCTL_STATE_CONNECTED.
432
if (state == ADHOCCTL_STATE_CONNECTED) {
433
// Checking pendingStatus to make sure ChangeStatus not to continously extending the delay ticks on every call for eternity
434
if (pendingStatus != SCE_UTILITY_STATUS_FINISHED) {
435
StartFade(false);
436
ChangeStatus(SCE_UTILITY_STATUS_FINISHED, NET_SHUTDOWN_DELAY_US);
437
}
438
439
// Let's not leaks any memory
440
if (Memory::IsValidAddress(scanInfosAddr))
441
userMemory.Free(scanInfosAddr);
442
scanInfosAddr = 0;
443
}
444
445
if ((request.netAction == NETCONF_JOIN_ADHOC || timedout) && IsButtonPressed(cancelButtonFlag)) {
446
StartFade(false);
447
ChangeStatus(SCE_UTILITY_STATUS_FINISHED, NET_SHUTDOWN_DELAY_US);
448
request.common.result = SCE_UTILITY_DIALOG_RESULT_ABORT;
449
// Let's not leaks any memory
450
if (Memory::IsValidAddress(scanInfosAddr))
451
userMemory.Free(scanInfosAddr);
452
scanInfosAddr = 0;
453
}
454
455
EndDraw();
456
}
457
458
if (ReadStatus() == SCE_UTILITY_STATUS_FINISHED || pendingStatus == SCE_UTILITY_STATUS_FINISHED)
459
Memory::Memcpy(requestAddr, &request, request.common.size, "NetConfDialogParam");
460
461
return 0;
462
}
463
464
int PSPNetconfDialog::Shutdown(bool force) {
465
if (ReadStatus() != SCE_UTILITY_STATUS_FINISHED && !force)
466
return SCE_ERROR_UTILITY_INVALID_STATUS;
467
468
PSPDialog::Shutdown(force);
469
if (!force) {
470
ChangeStatusShutdown(NET_SHUTDOWN_DELAY_US);
471
}
472
473
return 0;
474
}
475
476
void PSPNetconfDialog::DoState(PointerWrap &p) {
477
PSPDialog::DoState(p);
478
479
auto s = p.Section("PSPNetconfigDialog", 0, 2);
480
if (!s)
481
return;
482
483
Do(p, request);
484
if (s >= 2) {
485
Do(p, scanInfosAddr);
486
Do(p, scanStep);
487
Do(p, connResult);
488
}
489
else {
490
scanInfosAddr = 0;
491
scanStep = 0;
492
connResult = -1;
493
}
494
495
if (p.mode == p.MODE_READ) {
496
startTime = 0;
497
}
498
}
499
500
pspUtilityDialogCommon* PSPNetconfDialog::GetCommonParam()
501
{
502
return &request.common;
503
}
504
505