1
0
Fork 0
mirror of https://gitlab.com/niansa/llama_nds.git synced 2025-03-06 20:53:28 +01:00

Implemented initial working GUI

This commit is contained in:
niansa 2023-04-07 18:43:33 +02:00
parent d76d8ced9b
commit 42723347f1
15 changed files with 2987 additions and 375 deletions

View file

@ -24,91 +24,89 @@ void AsyncManager::cleanFutureMap(SockFutureMap& map) {
}
void AsyncManager::run() {
while (!stopping && runtime.cooperate()) {
// We should stop once there is nothing left to do
if (sockReads.empty() && sockWrites.empty()) [[unlikely]] {
break;
}
// We need to keep track of the highest fd for socket()
int maxFd = 0;
// Create except FD set
fd_set exceptFds;
FD_ZERO(&exceptFds);
// Create write FD set
fd_set writeFds;
FD_ZERO(&writeFds);
for (const auto& [fd, cb] : sockWrites) {
FD_SET(fd, &writeFds);
FD_SET(fd, &exceptFds);
if (fd > maxFd) {
maxFd = fd;
}
}
// Create read FD set
fd_set readFds;
FD_ZERO(&readFds);
for (const auto& [fd, cb] : sockReads) {
FD_SET(fd, &readFds);
FD_SET(fd, &exceptFds);
if (fd > maxFd) {
maxFd = fd;
}
}
// Specify timeout
timeval tv{
.tv_sec = 0,
.tv_usec = 250000
};
// select() until there is data
bool error = false;
if (select(maxFd+1, &readFds, &writeFds, &exceptFds, &tv) < 0) {
FD_ZERO(&readFds);
FD_ZERO(&writeFds);
error = true;
}
// Execution queue
std::vector<std::pair<SockFutureUnique&, bool>> execQueue;
// Collect all write futures
for (auto& [fd, future] : sockWrites) {
if (FD_ISSET(fd, &writeFds)) {
// Socket is ready for writing
execQueue.push_back({future, false});
}
if (FD_ISSET(fd, &exceptFds) || error) [[unlikely]] {
// An exception happened in the socket
execQueue.push_back({future, true});
}
}
// Collect all read futures
for (auto& [fd, future] : sockReads) {
if (FD_ISSET(fd, &readFds)) {
// Socket is ready for reading
execQueue.push_back({future, false});
}
if (FD_ISSET(fd, &exceptFds) || error) [[unlikely]] {
// An exception happened in the socket
execQueue.push_back({future, true});
}
}
// Set futures
for (auto& [future, value] : execQueue) {
future->set(value?AsyncResult::Error:AsyncResult::Success);
future = nullptr;
}
// Clean future maps
cleanFutureMap(sockWrites);
cleanFutureMap(sockReads);
// We should stop once there is nothing left to do
if (sockReads.empty() && sockWrites.empty()) [[unlikely]] {
stopping = true;
return;
}
stopping = false;
// We need to keep track of the highest fd for socket()
int maxFd = 0;
// Create except FD set
fd_set exceptFds;
FD_ZERO(&exceptFds);
// Create write FD set
fd_set writeFds;
FD_ZERO(&writeFds);
for (const auto& [fd, cb] : sockWrites) {
FD_SET(fd, &writeFds);
FD_SET(fd, &exceptFds);
if (fd > maxFd) {
maxFd = fd;
}
}
// Create read FD set
fd_set readFds;
FD_ZERO(&readFds);
for (const auto& [fd, cb] : sockReads) {
FD_SET(fd, &readFds);
FD_SET(fd, &exceptFds);
if (fd > maxFd) {
maxFd = fd;
}
}
// Specify timeout
timeval tv{
.tv_sec = 0,
.tv_usec = 250000
};
// select() until there is data
bool error = false;
if (select(maxFd+1, &readFds, &writeFds, &exceptFds, &tv) < 0) {
FD_ZERO(&readFds);
FD_ZERO(&writeFds);
error = true;
}
// Execution queue
std::vector<std::pair<SockFutureUnique&, bool>> execQueue;
// Collect all write futures
for (auto& [fd, future] : sockWrites) {
if (FD_ISSET(fd, &writeFds)) {
// Socket is ready for writing
execQueue.push_back({future, false});
}
if (FD_ISSET(fd, &exceptFds) || error) [[unlikely]] {
// An exception happened in the socket
execQueue.push_back({future, true});
}
}
// Collect all read futures
for (auto& [fd, future] : sockReads) {
if (FD_ISSET(fd, &readFds)) {
// Socket is ready for reading
execQueue.push_back({future, false});
}
if (FD_ISSET(fd, &exceptFds) || error) [[unlikely]] {
// An exception happened in the socket
execQueue.push_back({future, true});
}
}
// Set futures
for (auto& [future, value] : execQueue) {
future->set(value?AsyncResult::Error:AsyncResult::Success);
future = nullptr;
}
// Clean future maps
cleanFutureMap(sockWrites);
cleanFutureMap(sockReads);
}

View file

@ -38,6 +38,9 @@ public:
AsyncManager(const AsyncManager&) = delete;
AsyncManager(AsyncManager&&) = delete;
bool shouldRun() const {
return !stopping && runtime.cooperate();
}
void run();
void stop() {
stopping = true;

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)
project(llama.any LANGUAGES CXX)
project(llama.nds LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@ -12,21 +12,16 @@ add_executable(llama
Receiver.hpp Receiver.cpp
Sender.hpp Sender.cpp
AsyncManager.hpp AsyncManager.cpp
font.h font.c
NDSUI.hpp NDSUI.cpp
Runtime.cpp Runtime.hpp
basic-coro/AwaitableTask.hpp basic-coro/SingleEvent.hpp basic-coro/SingleEvent.cpp
)
target_compile_definitions(llama PUBLIC PLATFORM="${CMAKE_SYSTEM_NAME}")
if (CMAKE_SYSTEM_NAME STREQUAL Nintendo3DS)
target_compile_definitions(llama PUBLIC PLATFORM_3DS)
elseif (CMAKE_SYSTEM_NAME STREQUAL NintendoDS)
if (CMAKE_SYSTEM_NAME STREQUAL NintendoDS)
target_compile_definitions(llama PUBLIC PLATFORM_DS)
target_link_libraries(llama PUBLIC dswifi9 nds9)
elseif (CMAKE_SYSTEM_NAME STREQUAL Linux)
target_compile_definitions(llama PUBLIC PLATFORM_LINUX)
elseif (CMAKE_SYSTEM_NAME STREQUAL Windows)
target_compile_definitions(llama PUBLIC PLATFORM_WINDOWS)
target_link_libraries(llama PUBLIC Ws2_32)
else()
message(SEND_ERROR "${CMAKE_SYSTEM_NAME} is not a supported platform!")
endif()

View file

@ -17,27 +17,9 @@
void Client::fetchAddr(const std::string& addr, unsigned port) {
# ifdef HAS_ADDRINFO
// Set up hints
addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET; //TODO: Care about IPv6
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_CANONNAME;
// Get port as C string
char portStr[7];
sprintf(portStr, "%u", port);
// Get addrinfo
auto error = getaddrinfo(addr.c_str(), portStr, &hints, &addrInfo);
auto bad = addrInfo == nullptr;
# else
addrInfo = gethostbyname(addr.c_str());
auto error = errno;
auto bad = addrInfo == nullptr || addrInfo->h_addr_list[0] == nullptr;
# endif
// Check for error
if (bad) {
@ -55,12 +37,6 @@ Client::Client(const std::string& addr, unsigned port, AsyncManager& asyncManage
// Fetch address
fetchAddr(addr, port);
# ifdef HAS_ADDRINFO
// Connect to server
if (connect(*connection, addrInfo->ai_addr, addrInfo->ai_addrlen) != 0) [[unlikely]] {
throw Exception("Connection has been refused");
}
# else
// Connect to server
struct sockaddr_in sain;
sain.sin_family = AF_INET;
@ -69,7 +45,6 @@ Client::Client(const std::string& addr, unsigned port, AsyncManager& asyncManage
if (connect(*connection, reinterpret_cast<sockaddr *>(&sain), sizeof(sain)) != 0) [[unlikely]] {
throw Exception("Connection has been declined");
}
# endif
}
basiccoro::AwaitableTask<AsyncResult> Client::ask(std::string_view prompt, const std::function<basiccoro::AwaitableTask<void> (unsigned progress)>& on_progress, const std::function<basiccoro::AwaitableTask<void> (std::string_view token)>& on_token) {

View file

@ -28,13 +28,8 @@ class Client
AsyncManager& aMan;
int fd = -1;
# ifdef HAS_ADDRINFO
addrinfo
# else
bool sent = false;
hostent
# endif
*addrInfo; // Can't be null unless request has already been sent
hostent *addrInfo; // Can't be null unless request has already been sent
std::unique_ptr<SocketConnection<Sender::Simple, Receiver::Simple>> connection;

215
NDSUI.cpp Normal file
View file

@ -0,0 +1,215 @@
#include "NDSUI.hpp"
#include "font.h"
#include <exception>
#include <gl2d.h>
#include <nds.h>
#include <nds/touch.h>
#include <nds/input.h>
#define SCREEN_BORDER_PADDING 4
#define FONT_PADDING 1
#define INPUT_LINE_HEIGHT (FONT_HEIGHT+FONT_PADDING)
NDSUI *NDSUI::currentInstance;
consteval
unsigned NDSUI::calcMaxCharsInLine(unsigned int width) {
return width / (FONT_WIDTH + FONT_PADDING);
}
consteval
unsigned NDSUI::calcMaxLinesInRow(unsigned height) {
return height / (FONT_HEIGHT + FONT_PADDING);
}
void NDSUI::kbCallback(int key) {
if (key > 0) currentInstance->handleInput(static_cast<char>(key));
}
consteval
Box2D NDSUI::calcMessageLogDimensions() {
return {
{SCREEN_BORDER_PADDING, 0},
{SCREEN_WIDTH-SCREEN_BORDER_PADDING, SCREEN_HEIGHT-(SCREEN_BORDER_PADDING*2)-INPUT_LINE_HEIGHT}
};
}
void NDSUI::renderMessageLog() {
constexpr Box2D boxDims = calcMessageLogDimensions();
// Draw box
glBoxFilled(boxDims.topLeft.x, boxDims.topLeft.y, boxDims.bottomRight.x, boxDims.bottomRight.y, RGB15(6, 2, 14));
// Log messages renderer
auto renderLine = [this, y = int(boxDims.bottomRight.y - FONT_PADDING - FONT_HEIGHT), boxDims] (std::string_view line) mutable {
print(line, {boxDims.topLeft.x + FONT_PADDING, unsigned(y)}, RGB15(28, 28, 28));
y -= FONT_PADDING + FONT_HEIGHT;
if (y < 0) {
throw std::exception(); // Stop rendering any more lines
}
};
// Display line by line
try {
for (auto message = messages.rbegin(); message != messages.rend(); message++) {
const auto& lines = message->getLines();
for (auto line = lines.rbegin(); line != lines.rend(); line++) {
renderLine(*line);
}
}
} catch (...) {}
}
consteval
Box2D NDSUI::calcInputLineDimensions() {
return {
{SCREEN_BORDER_PADDING, SCREEN_HEIGHT-SCREEN_BORDER_PADDING-INPUT_LINE_HEIGHT},
{SCREEN_WIDTH-SCREEN_BORDER_PADDING, SCREEN_HEIGHT-SCREEN_BORDER_PADDING}
};
}
void NDSUI::renderInputLine() {
constexpr Box2D boxDims = calcInputLineDimensions();
constexpr Position2D textTopLeft{boxDims.topLeft.x+FONT_PADDING, boxDims.topLeft.y+FONT_PADDING};
// Draw box
glBoxFilled(boxDims.topLeft.x, boxDims.topLeft.y, boxDims.bottomRight.x, boxDims.bottomRight.y, RGB15(13, 8, 3));
// Measure amount of character that fit in
constexpr auto maxChars = calcMaxCharsInLine(boxDims.bottomRight.x - boxDims.topLeft.x);
// Mease amount of characters that don't fit in
unsigned startIdx = 0;
if (inputLineBufHead > maxChars) {
startIdx = inputLineBufHead - maxChars;
}
// Get that amount of characters
print(&inputLineBuf[startIdx], textTopLeft, RGB15(28, 28, 28));
}
bool NDSUI::printChar(const char character, Position2D *topleftpos, const int color) {
const bool *fontChar = font_get_character(character);
int x = 0;
int y = 0;
unsigned no = 0;
for (const bool *thispixel = fontChar; ; thispixel++) {
if (x == FONT_WIDTH) {
x = 0;
y++;
} if (y == FONT_HEIGHT) {
break;
} if (*thispixel) {
// Calculate spareout
unsigned spareout = font_pixels / 500;
// Skip pixel for spareout
if (!(no++ % spareout)) {
// Draw pixel with melonDS fallback for debug builds
# ifdef NDEBUG
glPutPixel(topleftpos->x + x, topleftpos->y + y, color);
# else
glBoxFilled(topleftpos->x + x, topleftpos->y + y, topleftpos->x + x, topleftpos->y + y, color);
# endif
font_pixels++;
}
}
x++;
}
return fontChar != fontBitmapUnk;
}
void NDSUI::print(std::string_view str, Position2D topleftpos, const int color) {
for (const char c : str) {
printChar(c, &topleftpos, color);
topleftpos.x += FONT_WIDTH + FONT_PADDING;
}
}
void NDSUI::handleInput(char c) {
//TODO: Check length
switch (c) {
case '\b': {
// Remove character if not at start
if (inputLineBufHead != 0) {
inputLineBuf[--inputLineBufHead] = '\0';
}
} break;
case '\n': {
if (userInputHandler && inputLineBuf[0]) {
auto msg = createLogMessage("User", inputLineBuf.data());
addLogMessage(std::move(msg));
userInputHandler->set(inputLineBuf.data());
resetInputLine();
//userInputHandler = nullptr;
}
} break;
default: {
// Add character if not at end
if (inputLineBufHead != inputLineBuf.size() - 1) {
inputLineBuf[inputLineBufHead] = c;
inputLineBuf[++inputLineBufHead] = '\0';
}
}
}
}
NDSUI::NDSUI() {
resetInputLine();
glScreen2D();
auto swkbd = keyboardDemoInit();
swkbd->OnKeyReleased = kbCallback;
keyboardShow();
}
void NDSUI::run() {
currentInstance = this;
font_pixels = 0;
// Update keyboard
keyboardUpdate();
// Draw
glBegin2D(); {
renderInputLine();
renderMessageLog();
} glEnd2D();
// Apply changes
glFlush(0);
swiWaitForVBlank();
}
LineWrappedString NDSUI::createLogMessage(const char *username, std::string_view message) {
// Do line-wrapping, create and return Message instance
return LineWrappedString(" "+std::string(username)+"\n"+std::string(message)+"\n", calcMaxCharsInLine(calcMessageLogDimensions().width()));
}
void LineWrappedString::split(std::string_view str, unsigned maxCharsPerLine) {
lines.clear();
const char *currStrStart = str.data();
const char *strEnd = str.data() + str.size();
for (size_t currStrLen = 0; ;) {
const char& c = currStrStart[currStrLen];
bool brk = false;
bool next = false;
bool minusOne = false;
if (c == '\n') {
next = true;
minusOne = true;
} else if (&c == strEnd) {
next = true;
brk = true;
minusOne = true;
} else if (currStrLen > maxCharsPerLine) {
next = true;
}
if (next) {
lines.push_back({currStrStart, currStrLen});
if (brk) break;
currStrStart += currStrLen + minusOne;
currStrLen = 0;
} else {
currStrLen++;
}
}
}

111
NDSUI.hpp Normal file
View file

@ -0,0 +1,111 @@
#ifndef NDSUI_HPP
#define NDSUI_HPP
#include "basic-coro/AwaitableTask.hpp"
#include "basic-coro/SingleEvent.hpp"
#include <memory>
#include <string>
#include <string_view>
#include <array>
#include <vector>
class LineWrappedString {
unsigned maxCharsPerLine;
std::vector<std::string> lines;
void split(std::string_view, unsigned maxCharsPerLine);
public:
LineWrappedString(std::string_view str, unsigned maxCharsPerLine) : maxCharsPerLine(maxCharsPerLine) {
split(str, maxCharsPerLine);
}
LineWrappedString(const LineWrappedString& o) : maxCharsPerLine(o.maxCharsPerLine), lines(o.lines) {}
LineWrappedString(LineWrappedString&& o) : maxCharsPerLine(o.maxCharsPerLine), lines(std::move(o.lines)) {}
auto& operator=(LineWrappedString&& o) {
maxCharsPerLine = o.maxCharsPerLine;
lines = std::move(o.lines);
return *this;
}
auto& operator=(const LineWrappedString& o) {
maxCharsPerLine = o.maxCharsPerLine;
lines = o.lines;
return *this;
}
const std::vector<std::string>& getLines() const {
return lines;
}
};
struct Position2D {
unsigned x, y;
};
struct Box2D {
Position2D topLeft, bottomRight;
constexpr
unsigned height() const {
return bottomRight.y - topLeft.y;
}
constexpr
unsigned width() const {
return bottomRight.x - topLeft.x;
}
};
class NDSUI {
static NDSUI *currentInstance; // Currently updating instance
std::array<char, 512> inputLineBuf;
unsigned inputLineBufHead = 0;
std::vector<LineWrappedString> messages;
std::unique_ptr<basiccoro::SingleEvent<std::string>> userInputHandler = nullptr;
size_t font_pixels;
static void kbCallback(int key);
static consteval
Box2D calcInputLineDimensions();
static consteval
Box2D calcMessageLogDimensions();
void renderMessageLog();
void renderInputLine();
static consteval
unsigned calcMaxCharsInLine(unsigned width);
static consteval
unsigned calcMaxLinesInRow(unsigned height);
bool printChar(const char character, Position2D *topleftpos, const int color);
void print(std::string_view str, Position2D topleftpos, const int color);
void handleInput(char);
void resetInputLine() {
inputLineBufHead = 0;
inputLineBuf[0] = '\0';
}
public:
NDSUI();
bool shouldRun() const {
return userInputHandler != nullptr;
}
void run();
auto& addLogMessage(LineWrappedString &&msg) {
return messages.emplace_back(std::move(msg));
}
basiccoro::AwaitableTask<std::string> readLine() {
userInputHandler = std::make_unique<std::remove_reference<decltype(*userInputHandler)>::type>();
co_return co_await *userInputHandler;
}
static
LineWrappedString createLogMessage(const char *username, std::string_view message);
};
#endif // NDSUI_HPP

View file

@ -3,6 +3,7 @@
#include <string_view>
#include <array>
#ifndef PLATFORM_WINDOWS
# include <sys/socket.h>
# include <sys/select.h>
#else
# include <ws2tcpip.h>

View file

@ -1,47 +0,0 @@
#include "Runtime.hpp"
#ifdef PLATFORM_3DS
#include <string>
#include <exception>
#include <cerrno>
#include <3ds.h>
void Runtime::customTerminate() noexcept {
// Get error message
std::string message;
try {
std::rethrow_exception(std::current_exception());
} catch (const std::exception& e) {
message = e.what();
} catch (...) {
message = "Unknown";
}
// Display error
errorConf conf = {
.type = ERROR_TEXT_WORD_WRAP,
.errorCode = errno,
.upperScreenFlag = ERROR_NORMAL,
.useLanguage = CFG_LANGUAGE_EN,
.Text = {L'I', L'N', L'V', L'A', L'L', L'I', L'D', L'\0'},
.homeButton = true,
.softwareReset = false,
.appJump = false,
.returnCode = ERROR_UNKNOWN,
.eulaVersion = 0
};
errorText(&conf, ("An exception was thrown but never handled:\n\n"+message).c_str());
errorDisp(&conf);
// Exit
aptExit();
socExit();
gfxExit();
exit(-errno);
}
#elif PLATFORM_DS
void Runtime::kbCallback(int key) {
if (key > 0) printf("%c", key);
}
#endif

View file

@ -1,77 +1,5 @@
#ifndef _RUNTIME_HPP
#define _RUNTIME_HPP
#ifdef PLATFORM_3DS
#include <iostream>
#include <string>
#include <string_view>
#include <thread>
#include <chrono>
#include <exception>
#include <stdexcept>
#include <cstring>
#include <malloc.h>
#include <3ds.h>
class Runtime {
u32 *SOC_buffer = NULL;
constexpr static auto SOC_ALIGN = 0x1000,
SOC_BUFFERSIZE = 0x100000;
[[noreturn]] static void customTerminate() noexcept;
public:
Runtime() {
std::set_terminate(customTerminate);
gfxInitDefault();
consoleInit(GFX_TOP, NULL);
aptInit();
SOC_buffer = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
auto ret = socInit(SOC_buffer, SOC_BUFFERSIZE);
if (ret != 0) {
throw std::runtime_error("socInit() = "+std::to_string((unsigned int)ret));
}
}
Runtime(Runtime&) = delete;
Runtime(const Runtime&) = delete;
Runtime(Runtime&&) = delete;
~Runtime() {
aptSetHomeAllowed(false);
std::cout << std::flush;
std::cerr << std::flush;
std::clog << std::endl << "Runtime destroyed." << std::endl;
std::clog << "Press START to exit" << std::flush;
for (u32 kDown; !(hidKeysDown() & KEY_START) && cooperate(); hidScanInput()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
aptExit();
socExit();
gfxExit();
}
static inline
bool cooperate() noexcept {
return aptMainLoop();
}
static const char *readInput(const char *hint) {
static SwkbdState swkbd;
static char swkbd_buf[2048];
// Read input
memset(swkbd_buf, 0, sizeof(swkbd_buf));
swkbdInit(&swkbd, SWKBD_TYPE_NORMAL, 3, sizeof(swkbd_buf));
swkbdSetHintText(&swkbd, hint);
swkbdInputText(&swkbd, swkbd_buf, sizeof(swkbd_buf));
// Return input as string
return swkbd_buf;
}
static void clearScreen() {
consoleClear();
}
};
#elif PLATFORM_DS
#include <iostream>
#include <string>
#include <string_view>
@ -85,12 +13,14 @@ public:
class Runtime {
static void kbCallback(int key);
Keyboard *swkbd;
public:
Runtime() {
// Configure displays
videoSetMode(MODE_0_3D);
lcdMainOnTop();
// Initialize console
consoleDemoInit();
@ -99,10 +29,6 @@ public:
if (!Wifi_InitDefault(WFC_CONNECT)) {
throw std::runtime_error("Failed to enable WiFi");
}
// Initialize keyboard
swkbd = keyboardDemoInit();
swkbd->OnKeyPressed = kbCallback;
}
Runtime(Runtime&) = delete;
Runtime(const Runtime&) = delete;
@ -126,114 +52,6 @@ public:
consoleClear();
}
};
#elif PLATFORM_LINUX
#include <iostream>
#include <stdexcept>
#include <mutex>
#include <cstring>
#include <csignal>
#include <cerrno>
class Runtime {
static inline bool stopping = false;
static inline void handler(int signo, siginfo_t *info, void *context) {
stopping = true;
}
public:
Runtime() {
struct sigaction act = { 0 };
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = handler;
for (int sig : {SIGTERM, SIGINT, SIGQUIT, SIGHUP}) {
if (sigaction(sig, &act, nullptr) < 0) {
throw std::runtime_error("sigaction() = "+std::string(strerror(errno)));
}
}
}
Runtime(Runtime&) = delete;
Runtime(const Runtime&) = delete;
Runtime(Runtime&&) = delete;
~Runtime() {
std::cout << std::flush;
std::cerr << std::flush;
std::clog << std::endl << "Runtime destroyed." << std::endl;
}
static inline bool cooperate() noexcept {
// Linux runs threads preemptively, no need to actually cooperate
return !stopping;
}
static const char *readInput(const char *hint) {
static std::string content;
std::cout << hint << ": ";
std::getline(std::cin, content);
return content.c_str();
}
static void clearScreen() {
std::cout << "\033[H\033[2J\033[3J";
}
};
#elif PLATFORM_WINDOWS
#include <iostream>
#include <mutex>
#include <stdexcept>
#include <winsock2.h>
class Runtime {
public:
Runtime() {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
throw std::runtime_error("Failed to initialize WinSock");
}
}
Runtime(Runtime&) = delete;
Runtime(const Runtime&) = delete;
Runtime(Runtime&&) = delete;
~Runtime() {
std::cout << std::flush;
std::cerr << std::flush;
std::clog << std::endl << "Runtime destroyed." << std::endl;
WSACleanup();
}
static constexpr bool cooperate() noexcept {
// Windows runs threads preemptively, no need to cooperate.
// No signals to handle either, Windows doesn't support them.
return true;
}
static const char *readInput(const char *hint) {
static std::string content;
std::cout << hint << ": ";
std::getline(std::cin, content);
return content.c_str();
}
static void clearScreen() {
system("cls");
}
};
#endif
#endif
#if !(defined(PLATFORM_WINDOWS) || defined(PLATFORM_DS))
# define MSG_FLAGS_OR_ZERO(...) __VA_ARGS__
#else
# define MSG_FLAGS_OR_ZERO(...) 0
#endif
#ifdef PLATFORM_DS
# define IPPROTO_TCP 0
#endif
#ifndef PLATFORM_DS
# define HAS_ADDRINFO
#define IPPROTO_TCP 0
#endif

View file

@ -4,6 +4,7 @@
#include <string_view>
#ifndef PLATFORM_WINDOWS
# include <sys/socket.h>
# include <sys/select.h>
#else
# include <ws2tcpip.h>
@ -25,5 +26,5 @@ basiccoro::AwaitableTask<AsyncResult> Sender::Simple::write(const std::byte *dat
}
// Write
co_return (send(fd, reinterpret_cast<const char*>(data), size, MSG_FLAGS_OR_ZERO(MSG_NOSIGNAL | (int(moreData)*MSG_MORE))) < 0)?AsyncResult::Error:AsyncResult::Success;
co_return (send(fd, reinterpret_cast<const char*>(data), size, 0) < 0)?AsyncResult::Error:AsyncResult::Success;
}

1760
font.c Normal file

File diff suppressed because it is too large Load diff

13
font.h Normal file
View file

@ -0,0 +1,13 @@
#include <stdbool.h>
#define FONT_HEIGHT 16
#define FONT_WIDTH 8
#define FONT_SIZE FONT_HEIGHT * FONT_WIDTH
#ifdef __cplusplus
extern "C" {
#endif
extern const bool fontBitmapUnk[FONT_SIZE];
const bool *font_get_character(const char character);
#ifdef __cplusplus
}
#endif

765
font_ugly.h Normal file
View file

@ -0,0 +1,765 @@
#include <stdbool.h>
#define FONT_HEIGHT 8
#define FONT_WIDTH 4
#define FONT_SIZE FONT_HEIGHT * FONT_WIDTH
const bool font_space[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
};
const bool font_unk[] = {
1, 1, 1, 1,
1, 0, 1, 1,
1, 1, 0, 1,
1, 0, 1, 1,
1, 1, 0, 1,
1, 0, 1, 1,
1, 1, 0, 1,
1, 1, 1, 1,
};
const bool font_digit_1[] = {
0, 0, 0, 1,
0, 1, 1, 1,
1, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
};
const bool font_digit_2[] = {
0, 1, 1, 0,
1, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
0, 1, 1, 0,
1, 0, 0, 0,
1, 0, 0, 0,
0, 1, 1, 1,
};
const bool font_digit_3[] = {
1, 1, 1, 0,
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
1, 1, 1, 0,
0, 0, 0, 1,
0, 0, 0, 1,
1, 1, 1, 0,
};
const bool font_digit_4[] = {
0, 0, 0, 1,
0, 0, 1, 0,
0, 1, 0, 0,
1, 0, 1, 0,
1, 1, 1, 1,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 0, 0,
};
const bool font_digit_5[] = {
1, 1, 1, 1,
1, 0, 0, 0,
1, 0, 0, 0,
0, 1, 1, 0,
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
1, 1, 1, 0,
};
const bool font_digit_6[] = {
0, 1, 1, 1,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
};
const bool font_digit_7[] = {
1, 1, 1, 1,
0, 0, 0, 1,
0, 0, 1, 0,
0, 0, 1, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
1, 0, 0, 0,
};
const bool font_digit_8[] = {
0, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
};
const bool font_digit_9[] = {
0, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 1,
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
1, 1, 1, 0,
};
const bool font_digit_0[] = {
0, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
};
const bool font_letter_a[] = {
0, 0, 0, 0,
1, 1, 1, 0,
0, 0, 0, 1,
0, 0, 0, 1,
0, 1, 1, 1,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
};
const bool font_letter_b[] = {
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
};
const bool font_letter_c[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 1, 1, 1,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
0, 1, 1, 1,
};
const bool font_letter_d[] = {
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
0, 1, 1, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
};
const bool font_letter_e[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 1, 1, 1,
1, 0, 0, 1,
1, 1, 1, 0,
1, 0, 0, 0,
0, 1, 1, 0,
};
const bool font_letter_f[] = {
0, 0, 1, 1,
0, 1, 0, 0,
0, 1, 0, 0,
1, 1, 1, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
};
const bool font_letter_g[] = {
0, 0, 0, 0,
0, 1, 1, 1,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
0, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
};
const bool font_letter_h[] = {
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
};
const bool font_letter_i[] = {
0, 0, 0, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 0, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
};
const bool font_letter_j[] = {
0, 0, 0, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 0, 0,
0, 0, 1, 0,
0, 0, 1, 0,
1, 0, 1, 0,
0, 1, 0, 0,
};
const bool font_letter_k[] = {
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 1,
1, 0, 1, 0,
1, 1, 0, 0,
1, 0, 1, 0,
1, 0, 0, 1,
};
const bool font_letter_l[] = {
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 1,
0, 0, 1, 0,
};
const bool font_letter_m[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 0, 0, 0,
1, 1, 0, 1,
1, 0, 1, 1,
1, 0, 1, 1,
1, 0, 1, 1,
};
const bool font_letter_n[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 0, 0, 0,
1, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
};
const bool font_letter_o[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
};
const bool font_letter_p[] = {
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
1, 1, 1, 0,
1, 0, 0, 0,
1, 0, 0, 0,
};
const bool font_letter_q[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 1,
0, 0, 0, 1,
0, 0, 0, 1,
};
const bool font_letter_r[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 0, 0, 0,
1, 1, 1, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
};
const bool font_letter_s[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 1, 1, 1,
1, 0, 0, 0,
0, 1, 1, 0,
0, 0, 0, 1,
1, 1, 1, 0,
};
const bool font_letter_t[] = {
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
1, 1, 1, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 0, 1, 1,
};
const bool font_letter_u[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
};
const bool font_letter_v[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
0, 1, 1, 0,
};
const bool font_letter_w[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 0, 0, 1,
1, 1, 1, 1,
1, 1, 1, 1,
0, 1, 1, 0,
};
const bool font_letter_x[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 0, 0, 1,
0, 1, 1, 0,
0, 1, 1, 0,
1, 0, 0, 1,
};
const bool font_letter_y[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 0, 0, 1,
0, 1, 1, 0,
0, 0, 1, 0,
0, 0, 0, 1,
};
const bool font_letter_z[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
1, 1, 1, 1,
0, 0, 0, 1,
0, 0, 1, 0,
0, 1, 0, 0,
1, 1, 1, 1,
};
const bool font_letter_A[] = {
0, 0, 0, 0,
0, 1, 1, 0,
0, 1, 1, 0,
1, 0, 0, 1,
1, 1, 1, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
};
const bool font_letter_B[] = {
1, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
1, 1, 1, 0,
};
const bool font_letter_C[] = {
0, 1, 1, 1,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
0, 1, 1, 1,
};
const bool font_letter_D[] = {
1, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 1, 1, 0,
};
const bool font_letter_E[] = {
1, 1, 1, 1,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 1, 1, 1,
1, 0, 0, 0,
1, 0, 0, 0,
1, 1, 1, 1,
};
const bool font_letter_F[] = {
1, 1, 1, 1,
1, 0, 0, 0,
1, 0, 0, 0,
1, 1, 1, 1,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
};
const bool font_letter_G[] = {
0, 1, 1, 1,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
};
const bool font_letter_H[] = {
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 1, 1, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
};
const bool font_letter_I[] = {
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
};
const bool font_letter_J[] = {
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
0, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
};
const bool font_letter_K[] = {
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 1, 0,
1, 1, 0, 0,
1, 0, 0, 0,
1, 1, 0, 0,
1, 0, 1, 0,
1, 0, 0, 1,
};
const bool font_letter_L[] = {
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 1, 1, 1,
};
const bool font_letter_M[] = {
1, 0, 0, 1,
1, 1, 1, 1,
1, 1, 1, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
};
const bool font_letter_N[] = {
1, 0, 0, 1,
1, 0, 0, 1,
1, 1, 0, 1,
1, 1, 0, 1,
1, 0, 1, 1,
1, 0, 1, 1,
1, 0, 0, 1,
1, 0, 0, 1,
};
const bool font_letter_O[] = {
0, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
};
const bool font_letter_P[] = {
1, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 1, 1, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
};
const bool font_letter_Q[] = {
0, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 1, 0, 1,
1, 0, 1, 1,
0, 1, 1, 1,
};
const bool font_letter_R[] = {
1, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 1, 1, 0,
1, 1, 0, 0,
1, 0, 1, 0,
1, 0, 0, 1,
};
const bool font_letter_S[] = {
0, 1, 1, 1,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
0, 1, 1, 0,
0, 0, 0, 1,
0, 0, 0, 1,
1, 1, 1, 0,
};
const bool font_letter_T[] = {
1, 1, 1, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
};
const bool font_letter_U[] = {
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
};
const bool font_letter_V[] = {
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
0, 1, 1, 0,
0, 1, 1, 0,
};
const bool font_letter_W[] = {
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
1, 1, 1, 1,
1, 1, 1, 1,
0, 1, 1, 0,
0, 1, 1, 0,
};
const bool font_letter_X[] = {
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
0, 1, 1, 0,
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
};
const bool font_letter_Y[] = {
1, 0, 0, 1,
1, 0, 0, 1,
1, 0, 0, 1,
0, 1, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 0, 1,
0, 0, 0, 1,
};
const bool font_letter_Z[] = {
1, 1, 1, 1,
0, 0, 0, 1,
0, 0, 1, 0,
0, 0, 1, 0,
0, 1, 0, 0,
0, 1, 0, 0,
1, 1, 0, 0,
1, 1, 1, 1,
};
const bool font_special_dot[] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 1, 0, 0,
};
const bool font_special_colon[] = {
0, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 1, 0, 0,
};
const bool font_special_exclaimationmark[] = {
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 0, 0, 0,
0, 1, 0, 0,
};
/*
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
*/
const bool *font_get_character(const char character) {
const bool *res = font_unk;
switch(character) {
case 'a': res = font_letter_a; break;
case 'b': res = font_letter_b; break;
case 'c': res = font_letter_c; break;
case 'd': res = font_letter_d; break;
case 'e': res = font_letter_e; break;
case 'f': res = font_letter_f; break;
case 'g': res = font_letter_g; break;
case 'h': res = font_letter_h; break;
case 'i': res = font_letter_i; break;
case 'j': res = font_letter_j; break;
case 'k': res = font_letter_k; break;
case 'l': res = font_letter_l; break;
case 'm': res = font_letter_m; break;
case 'n': res = font_letter_n; break;
case 'o': res = font_letter_o; break;
case 'p': res = font_letter_p; break;
case 'q': res = font_letter_q; break;
case 'r': res = font_letter_r; break;
case 's': res = font_letter_s; break;
case 't': res = font_letter_t; break;
case 'u': res = font_letter_u; break;
case 'v': res = font_letter_v; break;
case 'w': res = font_letter_w; break;
case 'x': res = font_letter_x; break;
case 'y': res = font_letter_y; break;
case 'z': res = font_letter_z; break;
case 'A': res = font_letter_A; break;
case 'B': res = font_letter_B; break;
case 'C': res = font_letter_C; break;
case 'D': res = font_letter_D; break;
case 'E': res = font_letter_E; break;
case 'F': res = font_letter_F; break;
case 'G': res = font_letter_G; break;
case 'H': res = font_letter_H; break;
case 'I': res = font_letter_I; break;
case 'J': res = font_letter_J; break;
case 'K': res = font_letter_K; break;
case 'L': res = font_letter_L; break;
case 'M': res = font_letter_M; break;
case 'N': res = font_letter_N; break;
case 'O': res = font_letter_O; break;
case 'P': res = font_letter_P; break;
case 'Q': res = font_letter_Q; break;
case 'R': res = font_letter_R; break;
case 'S': res = font_letter_S; break;
case 'T': res = font_letter_T; break;
case 'U': res = font_letter_U; break;
case 'V': res = font_letter_V; break;
case 'W': res = font_letter_W; break;
case 'X': res = font_letter_X; break;
case 'Y': res = font_letter_Y; break;
case 'Z': res = font_letter_Z; break;
case ' ': res = font_space; break;
case '1': res = font_digit_1; break;
case '2': res = font_digit_2; break;
case '3': res = font_digit_3; break;
case '4': res = font_digit_4; break;
case '5': res = font_digit_5; break;
case '6': res = font_digit_6; break;
case '7': res = font_digit_7; break;
case '8': res = font_digit_8; break;
case '9': res = font_digit_9; break;
case '0': res = font_digit_0; break;
case '.': res = font_special_dot; break;
case ':': res = font_special_colon; break;
case '!': res = font_special_exclaimationmark; break;
}
return res;
}

View file

@ -1,3 +1,4 @@
#include "NDSUI.hpp"
#include "Runtime.hpp"
#include "AsyncManager.hpp"
#include "Client.hpp"
@ -13,49 +14,57 @@ void on_progress(float progress) {
std::cout << unsigned(progress) << '\r' << std::flush;
}
basiccoro::AwaitableTask<void> async_main(Runtime& rt, AsyncManager &aMan) {
basiccoro::AwaitableTask<void> async_main(Runtime& rt, AsyncManager &aMan, NDSUI& ui) {
// Ask for server address
const std::string addr = rt.readInput("Server address");
ui.addLogMessage(ui.createLogMessage("System", "Please type in the address of the server."));
const std::string addr = co_await ui.readLine();
// Create client
Client client(addr, 99181, aMan);
// Greet the user
ui.addLogMessage(ui.createLogMessage("Bot", "Hey! How can I help you today?"));
// Connection loop
for (;; rt.cooperate()) {
// Read prompt
const auto prompt = rt.readInput("Prompt");
// Clear screen
rt.clearScreen();
const auto prompt = co_await ui.readLine();
// Display prompt
std::cout << "Prompt: " << prompt << std::endl;
auto& msg = ui.addLogMessage(ui.createLogMessage("Bot", "Initializing..."));
// Run inference
co_await client.ask(prompt, [&rt] (float progress) -> basiccoro::AwaitableTask<void> {
std::cout << unsigned(progress) << "%\r" << std::flush;
std::string result;
co_await client.ask(prompt, [&msg, &ui] (unsigned progress) -> basiccoro::AwaitableTask<void> {
msg = ui.createLogMessage("Bot", (std::to_string(progress)+"%"));
co_return;
}, [&rt] (std::string_view token) -> basiccoro::AwaitableTask<void> {
std::cout << token << std::flush;
}, [&result, &msg, &ui] (std::string_view token) -> basiccoro::AwaitableTask<void> {
result.append(token);
msg = ui.createLogMessage("Bot", result+"...");
co_return;
});
msg = ui.createLogMessage("Bot", result);
std::cout << "\n";
}
}
int main() {
Runtime rt;
NDSUI ui;
AsyncManager aMan(rt);
// Print header
std::cout << "llama.any running on " PLATFORM ".\n"
std::cout << "llama.nds running on " PLATFORM ".\n"
"\n";
// Start async main()
async_main(rt, aMan);
async_main(rt, aMan, ui);
// Start async manager
aMan.run();
while (aMan.shouldRun() || ui.shouldRun()) {
ui.run();
aMan.run();
}
return 0;
}