kpmpgsmkii/client/src/main.c

292 lines
8.2 KiB
C

/*
* Kangaroo Punch MultiPlayer Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/*
* To Do:
*
* - Replace any direct data manipulation from outside a class with methods to handle it
* - More widget states: Ghosted (underway)
* - Methods that can change the width of a widget (such as setTitle) need to repaint the parent window as well
* - Metrics, colors, etc. should be defined in each widget and not in GUI
* - Widgets should support a "changed" callback that can cancel the change
* - Use LabelT in all widgets that have a label
* - Find a light grey to replace white widget data areas
* - No thumb in listbox scrollbar
* - Layout container widgets!
* - Fix variable names. something = local; _something = file global; __something = project global
*/
#include "stddclmr.h"
#include "os.h"
#include "vesa.h"
#include "surface.h"
#include "mouse.h"
#include "keyboard.h"
#include "task.h"
#include "image.h"
#include "font.h"
#include "timer.h"
#include "gui.h"
#include "config.h"
#include "runtime.h"
#include "welcome.h"
PacketThreadDataT *__packetThreadData = NULL; // Exported in os.h
RuntimeDataT __runtimeData; // Exported in runtime.h
static void taskComDebugLoop(void *data);
static void taskGuiEventLoop(void *data);
#include "comport.h"
static void taskComDebugLoop(void *data) {
int32_t r;
int32_t x;
char buffer[1024];
(void)data;
// Open COM port.
logWrite("Opening COM\n");
r = comOpen(__configData.serialCom - 1, 57600L, 8, 'n', 1, SER_HANDSHAKING_RTSCTS);
if (r != SER_SUCCESS) {
logWrite("Unable to open COM port! Please check settings.\n");
guiStop();
return;
}
// Send a CR to clear anything in the modem.
logWrite("Clearing modem buffer\n");
snprintf(buffer, 1023, "%c", 13);
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
// Wait roughly a second for anything.
comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4, "weExpectNothing");
// Send actual init
logWrite("Init modem\n");
snprintf(buffer, 1023, "%s%c", "AT+SOCK1", 13);
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
// Wait roughly a second for "OK".
r = comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4, "OK");
if (r <= 0) {
comClose(__configData.serialCom - 1);
logWrite("Modem does not support ENET! Please check settings.\n");
guiStop();
return;
}
logWrite("Modem OK\n");
// Flush COM port.
timerQuarterSecondsWait(4);
comReceiveBufferFlush(__configData.serialCom - 1);
// Show dialing, dial service.
logWrite("Dialing\n");
snprintf(buffer, 1023, "ATDT%s:%d%c", __configData.serverHost, __configData.serverPort, 13);
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
// Wait 7 seconds for welcome banner.
r = comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4 * 7, "KPMPGSMKII\r");
if (r <= 0) {
comClose(__configData.serialCom - 1);
logWrite("Unable to connect to server! Please check settings or try later.\n");
guiStop();
return;
}
// Connected! Show icon and negotiate session.
logWrite("Connected\n");
packetEncryptionSetup(__packetThreadData);
PacketEncodeDataT encoded = { 0 };
PacketDecodeDataT decoded = { 0 };
// Send it 10 times, waiting for a PONG between each.
for (x=0; x<10; x++) {
// Send PING.
logWrite("Sending PING %d\n", x);
encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_PING;
encoded.channel = 1;
encoded.encrypt = 0;
packetEncode(__packetThreadData, &encoded, NULL, 0); // Must encode each packet - no reusing encoded data.
packetSend(__packetThreadData, &encoded);
// Wait for PONG.
while (!guiHasStopped()) {
r = comRead(__configData.serialCom - 1, buffer, 1);
if (r == 1) {
if (packetDecode(__packetThreadData, &decoded, buffer, 1)) {
if (decoded.packetType == PACKET_TYPE_PONG) {
logWrite("Received PONG\n");
break;
} else {
logWrite("Unexpected packet type received %d\n", decoded.packetType);
}
}
} else {
taskYield();
}
}
}
if (guiHasStopped()) return;
// Send LOGIN.
logWrite("Sending LOGIN\n");
PacketTypeLoginT loginData;
strcpy(loginData.user, "Encryption");
strcpy(loginData.pass, "Works!");
encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_LOGIN;
encoded.channel = 1;
encoded.encrypt = 1;
packetEncode(__packetThreadData, &encoded, (char *)&loginData, sizeof(PacketTypeLoginT)); // Must encode each packet - no reusing encoded data.
packetSend(__packetThreadData, &encoded);
// Send CLIENT_SHUTDOWN.
logWrite("Sending CLIENT_SHUTDOWN\n");
encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_CLIENT_SHUTDOWN;
encoded.channel = 1;
encoded.encrypt = 0;
packetEncode(__packetThreadData, &encoded, NULL, 0);
packetSend(__packetThreadData, &encoded);
logWrite("Sleeping\n");
timerQuarterSecondsWait(8);
logWrite("COM closed\n");
comClose(__configData.serialCom - 1);
guiStop();
}
static void taskGuiEventLoop(void *data) {
MouseT *mouse = NULL;
ImageT *pointer = NULL;
ColorT alpha = { 0 };
(void)data;
pointer = imageLoad("data/mouse.png");
alpha = imagePixelGet(pointer, 5, 0);
do {
timerUpdate();
mouse = mouseRead();
if (keyHit()) {
guiKeyboardProcess(keyASCIIGet(), keyExtendedGet(), keyScanCodeGet(), keyShiftGet(), keyControlGet(), keyAltGet());
//logWrite("Key '%d' Extended '%d' Scancode '%d' Shift '%d' Control '%d' Alt '%d'\n", keyASCIIGet(), keyExtended(), keyScanCode(), keyShift(), keyControl(), keyAlt());
if (keyASCIIGet() == 27) guiStop();
}
guiMouseProcess(mouse);
guiComposite();
imageRenderWithAlpha(pointer, mouse->x, mouse->y, alpha);
vbeVBlankWait();
vbePresent();
taskYield();
} while (!guiHasStopped());
imageUnload(&pointer);
}
int main(int argc, char *argv[]) {
#ifndef __linux__
// On DOS, display the contets of the log now that we're back in text mode.
char *logName = NULL;
FILE *in = NULL;
#endif
memoryStartup(argv[0]);
logOpenByHandle(memoryLogHandleGet());
configStartup(argv[0]);
// 0 1 2 3 4 5 6 7 8
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
logWrite("%s", "Kangaroo Punch MultiPlayer DOS Game Client Mark II\n");
logWrite("%s", "Copyright (C) 2020-2021 Scott Duensing scott@kangaroopunch.com\n\n");
if (argc > 1) {
if (strcmp(argv[1], "/?") == 0) {
vbeInfoShow();
configShutdown();
logClose();
memoryShutdown();
return 0;
}
}
// Do we have the video mode they asked for?
if (vbeStartup(__configData.videoWidth, __configData.videoHeight, __configData.videoDepth)) {
configShutdown();
logClose();
memoryShutdown();
return 1;
}
surfaceStartup();
mouseStartup();
timerStartup();
guiStartup();
taskStartup();
__packetThreadData = packetThreadDataCreate(NULL);
packetSenderRegister(comPacketSender);
//taskCreate(taskComDebugLoop, NULL);
taskCreate(taskWelcome, NULL);
taskCreate(taskGuiEventLoop, NULL);
taskRun();
packetThreadDataDestroy(&__packetThreadData);
taskShutdown();
guiShutdown();
timerShutdown();
mouseShutdown();
surfaceShutdown();
vbeShutdown();
configShutdown();
logClose();
memoryShutdown();
#ifndef __linux__
//***TODO*** Why the frack does this not work?!
textmode(C80);
// On DOS, display the contets of the log now that we're back in text mode.
logName = utilAppNameWithNewExtensionGet(argv[0], "log");
in = fopen(logName, "r");
if (in) {
while (!feof(in)) {
putc(fgetc(in), stdout);
}
fclose(in);
free(in);
}
free(logName);
_Exit(0);
#endif
return 0;
}