mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-08-28 13:16:41 +00:00
pull in project-slippi/Ishiiruka/pull/245
Chat Animations
This commit is contained in:
parent
db20109cbe
commit
7aa63ea200
6 changed files with 755 additions and 1 deletions
Binary file not shown.
Binary file not shown.
|
@ -490,6 +490,7 @@ add_library(core
|
||||||
Slippi/SlippiUser.h
|
Slippi/SlippiUser.h
|
||||||
Slippi/SlippiGameReporter.cpp
|
Slippi/SlippiGameReporter.cpp
|
||||||
Slippi/SlippiGameReporter.h
|
Slippi/SlippiGameReporter.h
|
||||||
|
Slippi/SlippiPremadeText.h
|
||||||
)
|
)
|
||||||
|
|
||||||
if(_M_X86)
|
if(_M_X86)
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
#include "Core/Slippi/SlippiMatchmaking.h"
|
#include "Core/Slippi/SlippiMatchmaking.h"
|
||||||
#include "Core/Slippi/SlippiPlayback.h"
|
#include "Core/Slippi/SlippiPlayback.h"
|
||||||
|
#include "Core/Slippi/SlippiPremadeText.h"
|
||||||
#include "Core/Slippi/SlippiReplayComm.h"
|
#include "Core/Slippi/SlippiReplayComm.h"
|
||||||
#include "Core/State.h"
|
#include "Core/State.h"
|
||||||
|
|
||||||
|
@ -2022,7 +2023,7 @@ void CEXISlippi::prepareOnlineMatchState()
|
||||||
|
|
||||||
#ifdef LOCAL_TESTING
|
#ifdef LOCAL_TESTING
|
||||||
localPlayerIndex = 0;
|
localPlayerIndex = 0;
|
||||||
chatMessageId = localChatMessageId;
|
sentChatMessageId = localChatMessageId;
|
||||||
chatMessagePlayerIdx = 0;
|
chatMessagePlayerIdx = 0;
|
||||||
localChatMessageId = 0;
|
localChatMessageId = 0;
|
||||||
// in CSS p1 is always current player and p2 is opponent
|
// in CSS p1 is always current player and p2 is opponent
|
||||||
|
@ -2042,8 +2043,15 @@ void CEXISlippi::prepareOnlineMatchState()
|
||||||
chatMessageId = remoteMessageSelection.messageId;
|
chatMessageId = remoteMessageSelection.messageId;
|
||||||
chatMessagePlayerIdx = remoteMessageSelection.playerIdx;
|
chatMessagePlayerIdx = remoteMessageSelection.playerIdx;
|
||||||
sentChatMessageId = slippi_netplay->GetSlippiRemoteSentChatMessage();
|
sentChatMessageId = slippi_netplay->GetSlippiRemoteSentChatMessage();
|
||||||
|
// If connection is 1v1 set index 0 for local and 1 for remote
|
||||||
|
if ((matchmaking && matchmaking->RemotePlayerCount() == 1) || !matchmaking)
|
||||||
|
{
|
||||||
|
chatMessagePlayerIdx = sentChatMessageId > 0 ? localPlayerIndex : remotePlayerIndex;
|
||||||
|
}
|
||||||
// in CSS p1 is always current player and p2 is opponent
|
// in CSS p1 is always current player and p2 is opponent
|
||||||
localPlayerName = p1Name = userInfo.display_name;
|
localPlayerName = p1Name = userInfo.display_name;
|
||||||
|
INFO_LOG_FMT(SLIPPI, "chatMessagePlayerIdx {} {}", chatMessagePlayerIdx,
|
||||||
|
matchmaking ? matchmaking->RemotePlayerCount() : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> leftTeamPlayers = {};
|
std::vector<u8> leftTeamPlayers = {};
|
||||||
|
@ -2407,6 +2415,58 @@ void CEXISlippi::prepareGctLoad(u8* payload)
|
||||||
m_read_queue.insert(m_read_queue.end(), gct.begin(), gct.end());
|
m_read_queue.insert(m_read_queue.end(), gct.begin(), gct.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<u8> CEXISlippi::loadPremadeText(u8* payload)
|
||||||
|
{
|
||||||
|
u8 textId = payload[0];
|
||||||
|
std::vector<u8> premadeTextData;
|
||||||
|
auto spt = SlippiPremadeText();
|
||||||
|
|
||||||
|
if (textId >= SlippiPremadeText::SPT_CHAT_P1 && textId <= SlippiPremadeText::SPT_CHAT_P4)
|
||||||
|
{
|
||||||
|
auto port = textId - 1;
|
||||||
|
std::string playerName;
|
||||||
|
if (matchmaking)
|
||||||
|
playerName = matchmaking->GetPlayerName(port);
|
||||||
|
#ifdef LOCAL_TESTING
|
||||||
|
std::string defaultNames[] = {"Player 1", "lol u lost 2 dk", "Player 3", "Player 4"};
|
||||||
|
playerName = defaultNames[port];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
u8 paramId = payload[1] == 0x83 ?
|
||||||
|
0x88 :
|
||||||
|
payload[1]; // TODO: Figure out what the hell is going on and fix this
|
||||||
|
|
||||||
|
auto chatMessage = spt.premadeTextsParams[paramId];
|
||||||
|
std::string param = ReplaceAll(chatMessage.c_str(), " ", "<S>");
|
||||||
|
playerName = ReplaceAll(playerName.c_str(), " ", "<S>");
|
||||||
|
premadeTextData = spt.GetPremadeTextData(textId, playerName.c_str(), param.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
premadeTextData = spt.GetPremadeTextData(textId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return premadeTextData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CEXISlippi::preparePremadeTextLength(u8* payload)
|
||||||
|
{
|
||||||
|
std::vector<u8> premadeTextData = loadPremadeText(payload);
|
||||||
|
|
||||||
|
m_read_queue.clear();
|
||||||
|
// Write size to output
|
||||||
|
appendWordToBuffer(&m_read_queue, static_cast<u32>(premadeTextData.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CEXISlippi::preparePremadeTextLoad(u8* payload)
|
||||||
|
{
|
||||||
|
std::vector<u8> premadeTextData = loadPremadeText(payload);
|
||||||
|
|
||||||
|
m_read_queue.clear();
|
||||||
|
// Write data to output
|
||||||
|
m_read_queue.insert(m_read_queue.end(), premadeTextData.begin(), premadeTextData.end());
|
||||||
|
}
|
||||||
|
|
||||||
void CEXISlippi::handleChatMessage(u8* payload)
|
void CEXISlippi::handleChatMessage(u8* payload)
|
||||||
{
|
{
|
||||||
int messageId = payload[0];
|
int messageId = payload[0];
|
||||||
|
@ -2697,6 +2757,12 @@ void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize)
|
||||||
case CMD_FILE_LOAD:
|
case CMD_FILE_LOAD:
|
||||||
prepareFileLoad(&memPtr[bufLoc + 1]);
|
prepareFileLoad(&memPtr[bufLoc + 1]);
|
||||||
break;
|
break;
|
||||||
|
case CMD_PREMADE_TEXT_LENGTH:
|
||||||
|
preparePremadeTextLength(&memPtr[bufLoc + 1]);
|
||||||
|
break;
|
||||||
|
case CMD_PREMADE_TEXT_LOAD:
|
||||||
|
preparePremadeTextLoad(&memPtr[bufLoc + 1]);
|
||||||
|
break;
|
||||||
case CMD_OPEN_LOGIN:
|
case CMD_OPEN_LOGIN:
|
||||||
handleLogInRequest();
|
handleLogInRequest();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -82,6 +82,8 @@ private:
|
||||||
CMD_GCT_LENGTH = 0xD3,
|
CMD_GCT_LENGTH = 0xD3,
|
||||||
CMD_GCT_LOAD = 0xD4,
|
CMD_GCT_LOAD = 0xD4,
|
||||||
CMD_GET_DELAY = 0xD5,
|
CMD_GET_DELAY = 0xD5,
|
||||||
|
CMD_PREMADE_TEXT_LENGTH = 0xE1,
|
||||||
|
CMD_PREMADE_TEXT_LOAD = 0xE2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -130,6 +132,8 @@ private:
|
||||||
{CMD_GCT_LENGTH, 0x0},
|
{CMD_GCT_LENGTH, 0x0},
|
||||||
{CMD_GCT_LOAD, 0x4},
|
{CMD_GCT_LOAD, 0x4},
|
||||||
{CMD_GET_DELAY, 0x0},
|
{CMD_GET_DELAY, 0x0},
|
||||||
|
{CMD_PREMADE_TEXT_LENGTH, 0x0},
|
||||||
|
{CMD_PREMADE_TEXT_LOAD, 0x4},
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WriteMessage
|
struct WriteMessage
|
||||||
|
@ -198,6 +202,10 @@ private:
|
||||||
void prepareGctLength();
|
void prepareGctLength();
|
||||||
void prepareGctLoad(u8* payload);
|
void prepareGctLoad(u8* payload);
|
||||||
void prepareDelayResponse();
|
void prepareDelayResponse();
|
||||||
|
void preparePremadeTextLength(u8* payload);
|
||||||
|
void preparePremadeTextLoad(u8* payload);
|
||||||
|
std::vector<u8> loadPremadeText(u8* payload);
|
||||||
|
int getCharColor(u8 charId, u8 teamId);
|
||||||
|
|
||||||
void FileWriteThread(void);
|
void FileWriteThread(void);
|
||||||
|
|
||||||
|
|
679
Source/Core/Core/Slippi/SlippiPremadeText.h
Normal file
679
Source/Core/Core/Slippi/SlippiPremadeText.h
Normal file
|
@ -0,0 +1,679 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class SlippiPremadeText
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SPT_CHAT_P1 = 0x1,
|
||||||
|
SPT_CHAT_P2 = 0x2,
|
||||||
|
SPT_CHAT_P3 = 0x3,
|
||||||
|
SPT_CHAT_P4 = 0x4,
|
||||||
|
SPT_LOGOUT = 0x5,
|
||||||
|
|
||||||
|
CHAT_MSG_U_PAD_LEFT = 0x81,
|
||||||
|
CHAT_MSG_U_PAD_RIGHT = 0x82,
|
||||||
|
CHAT_MSG_U_PAD_DOWN = 0x84,
|
||||||
|
CHAT_MSG_U_PAD_UP = 0x88,
|
||||||
|
|
||||||
|
CHAT_MSG_L_PAD_LEFT = 0x11,
|
||||||
|
CHAT_MSG_L_PAD_RIGHT = 0x12,
|
||||||
|
CHAT_MSG_L_PAD_DOWN = 0x14,
|
||||||
|
CHAT_MSG_L_PAD_UP = 0x18,
|
||||||
|
|
||||||
|
CHAT_MSG_R_PAD_LEFT = 0x21,
|
||||||
|
CHAT_MSG_R_PAD_RIGHT = 0x22,
|
||||||
|
CHAT_MSG_R_PAD_DOWN = 0x24,
|
||||||
|
CHAT_MSG_R_PAD_UP = 0x28,
|
||||||
|
|
||||||
|
CHAT_MSG_D_PAD_LEFT = 0x41,
|
||||||
|
CHAT_MSG_D_PAD_RIGHT = 0x42,
|
||||||
|
CHAT_MSG_D_PAD_DOWN = 0x44,
|
||||||
|
CHAT_MSG_D_PAD_UP = 0x48,
|
||||||
|
};
|
||||||
|
|
||||||
|
unordered_map<u8, string> premadeTextsParams = {
|
||||||
|
|
||||||
|
{CHAT_MSG_U_PAD_UP, "ggs"},
|
||||||
|
{CHAT_MSG_U_PAD_LEFT, "one more"},
|
||||||
|
{CHAT_MSG_U_PAD_RIGHT, "brb"},
|
||||||
|
{CHAT_MSG_U_PAD_DOWN, "good luck"},
|
||||||
|
|
||||||
|
{CHAT_MSG_L_PAD_UP, "well played"},
|
||||||
|
{CHAT_MSG_L_PAD_LEFT, "that was fun"},
|
||||||
|
{CHAT_MSG_L_PAD_RIGHT, "thanks"},
|
||||||
|
{CHAT_MSG_L_PAD_DOWN, "too good"},
|
||||||
|
|
||||||
|
{CHAT_MSG_R_PAD_UP, "oof"},
|
||||||
|
{CHAT_MSG_R_PAD_LEFT, "my b"},
|
||||||
|
{CHAT_MSG_R_PAD_RIGHT, "lol"},
|
||||||
|
{CHAT_MSG_R_PAD_DOWN, "wow"},
|
||||||
|
|
||||||
|
{CHAT_MSG_D_PAD_UP, "okay"},
|
||||||
|
{CHAT_MSG_D_PAD_LEFT, "thinking"},
|
||||||
|
{CHAT_MSG_D_PAD_RIGHT, "lets play again later"},
|
||||||
|
{CHAT_MSG_D_PAD_DOWN, "bad connection"},
|
||||||
|
};
|
||||||
|
|
||||||
|
unordered_map<u8, string> premadeTexts = {
|
||||||
|
{SPT_CHAT_P1, "<LEFT><KERN><COLOR, 229, 76, 76>%s-<S><COLOR, 255, 255, 255>%s<END>"},
|
||||||
|
{SPT_CHAT_P2, "<LEFT><KERN><COLOR, 59, 189, 255>%s-<S><COLOR, 255, 255, 255>%s<END>"},
|
||||||
|
{SPT_CHAT_P3, "<LEFT><KERN><COLOR, 255, 203, 4>%s-<S><COLOR, 255, 255, 255>%s<END>"},
|
||||||
|
{SPT_CHAT_P4, "<LEFT><KERN><COLOR, 0, 178, 2>%s-<S><COLOR, 255, 255, 255>%s<END>"},
|
||||||
|
{SPT_LOGOUT, "<FIT><COLOR, 243, 75, 75>Are<S>You<COLOR, 0, 175, 75><S>Sure?<END>"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: use va_list to handle any no. or args
|
||||||
|
string GetPremadeTextString(u8 textId) { return premadeTexts[textId]; }
|
||||||
|
|
||||||
|
vector<u8> GetPremadeTextData(u8 textId, ...)
|
||||||
|
{
|
||||||
|
string format = GetPremadeTextString(textId);
|
||||||
|
char str[400];
|
||||||
|
va_list args;
|
||||||
|
va_start(args, textId);
|
||||||
|
vsprintf(str, format.c_str(), args);
|
||||||
|
va_end(args);
|
||||||
|
// INFO_LOG(SLIPPI, "%s", str);
|
||||||
|
|
||||||
|
vector<u8> data = {};
|
||||||
|
vector<u8> empty = {};
|
||||||
|
|
||||||
|
vector<string> matches = vector<string>();
|
||||||
|
|
||||||
|
// NOTE: This code is converted from HSDRaw C# code
|
||||||
|
// Fuck Regex, current cpp version does not support positive lookaheads to match this pattern
|
||||||
|
// "((?<=<).+?(?=>))|((?<=>*)([^>]+?)(?=<) Good ol' fashioned nested loop :)
|
||||||
|
auto splitted = split(str, ">");
|
||||||
|
for (int i = 0; i < splitted.size(); i++)
|
||||||
|
{
|
||||||
|
auto splitted2 = split(splitted[i], "<");
|
||||||
|
for (int j = 0; j < splitted2.size(); j++)
|
||||||
|
{
|
||||||
|
if (splitted2[j].length() > 0)
|
||||||
|
matches.push_back(splitted2[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string match;
|
||||||
|
for (int m = 0; m < matches.size(); m++)
|
||||||
|
{
|
||||||
|
match = matches[m];
|
||||||
|
|
||||||
|
auto splittedMatches = split(match, ",");
|
||||||
|
if (splittedMatches.size() == 0)
|
||||||
|
continue;
|
||||||
|
string firstMatch = splittedMatches[0];
|
||||||
|
|
||||||
|
pair<TEXT_OP_CODE, pair<string, string>> key = findCodeKey(firstMatch);
|
||||||
|
if (key.first != TEXT_OP_CODE::CUSTOM_NULL)
|
||||||
|
{
|
||||||
|
if (splittedMatches.size() - 1 != strlen(key.second.second.c_str()))
|
||||||
|
return empty;
|
||||||
|
|
||||||
|
data.push_back((u8)key.first);
|
||||||
|
|
||||||
|
string res;
|
||||||
|
string res2;
|
||||||
|
for (int j = 0; j < strlen(key.second.second.c_str()); j++)
|
||||||
|
{
|
||||||
|
switch (key.second.second.c_str()[j])
|
||||||
|
{
|
||||||
|
case 'b':
|
||||||
|
res = splittedMatches[j + 1];
|
||||||
|
trim(res);
|
||||||
|
if ((u8)atoi(res.c_str()))
|
||||||
|
data.push_back((u8)atoi(res.c_str()));
|
||||||
|
else
|
||||||
|
data.push_back(0);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
res2 = splittedMatches[j + 1];
|
||||||
|
trim(res2);
|
||||||
|
u16 sht = (u16)atoi(res2.c_str());
|
||||||
|
if (sht)
|
||||||
|
{
|
||||||
|
data.push_back((u8)(sht >> 8));
|
||||||
|
data.push_back((u8)(sht & 0xFF));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.push_back(0);
|
||||||
|
data.push_back(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// process string otherwise
|
||||||
|
|
||||||
|
if (splittedMatches.size() >= 2 && firstMatch == "CHR")
|
||||||
|
{
|
||||||
|
string res3 = splittedMatches[1];
|
||||||
|
trim(res3);
|
||||||
|
u16 ch = (u16)atoi(res3.c_str());
|
||||||
|
if (ch)
|
||||||
|
{
|
||||||
|
u16 sht = (u16)(((u16)TEXT_OP_CODE::SPECIAL_CHARACTER << 8) | ch);
|
||||||
|
u8 r = (u8)(sht >> 8);
|
||||||
|
u8 r2 = (u8)(sht & 0xFF);
|
||||||
|
data.push_back(r);
|
||||||
|
data.push_back(r2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int c = 0; c < strlen(firstMatch.c_str()); c++)
|
||||||
|
{
|
||||||
|
char chr = firstMatch[c];
|
||||||
|
|
||||||
|
// Yup, fuck strchr and cpp too, I'm not in the mood to spend 4 more hours researching
|
||||||
|
// how to get Japanese characters properly working with a map, so I put everything on an
|
||||||
|
// int array in hex
|
||||||
|
int pos = -1;
|
||||||
|
for (int ccc = 0; ccc < 287; ccc++)
|
||||||
|
{
|
||||||
|
if ((char)CHAR_MAP[ccc] == chr)
|
||||||
|
{
|
||||||
|
pos = ccc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos >= 0)
|
||||||
|
{
|
||||||
|
u16 sht = (u16)(((u16)TEXT_OP_CODE::COMMON_CHARACTER << 8) | pos);
|
||||||
|
u8 r = (u8)(sht >> 8);
|
||||||
|
u8 r2 = (u8)(sht & 0xFF);
|
||||||
|
// INFO_LOG(SLIPPI, "%x %x %x %c", sht, r, r2, chr);
|
||||||
|
|
||||||
|
data.push_back(r);
|
||||||
|
data.push_back(r2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// INFO_LOG(SLIPPI, "DATA:");
|
||||||
|
// for(int i=0;i<data.size();i++){
|
||||||
|
// INFO_LOG(SLIPPI, "%x", data[i]);
|
||||||
|
// }
|
||||||
|
data.push_back(0x00); // Always add end, just in case
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum TEXT_OP_CODE
|
||||||
|
{
|
||||||
|
END = 0x00,
|
||||||
|
RESET = 0x01,
|
||||||
|
UNKNOWN_02 = 0x02,
|
||||||
|
LINE_BREAK = 0x03,
|
||||||
|
UNKNOWN_04 = 0x04,
|
||||||
|
UNKNOWN_05 = 0x05,
|
||||||
|
UNKNOWN_06 = 0x06,
|
||||||
|
OFFSET = 0x07,
|
||||||
|
UNKNOWN_08 = 0x08,
|
||||||
|
UNKNOWN_09 = 0x09,
|
||||||
|
SCALING = 0x0A,
|
||||||
|
RESET_SCALING = 0x0B,
|
||||||
|
COLOR = 0x0C,
|
||||||
|
CLEAR_COLOR = 0x0D,
|
||||||
|
SET_TEXTBOX = 0x0E,
|
||||||
|
RESET_TEXTBOX = 0x0F,
|
||||||
|
CENTERED = 0x10,
|
||||||
|
RESET_CENTERED = 0x11,
|
||||||
|
LEFT_ALIGNED = 0x12,
|
||||||
|
RESET_LEFT_ALIGN = 0x13,
|
||||||
|
RIGHT_ALIGNED = 0x14,
|
||||||
|
RESET_RIGHT_ALIGN = 0x15,
|
||||||
|
KERNING = 0x16,
|
||||||
|
NO_KERNING = 0x17,
|
||||||
|
FITTING = 0x18,
|
||||||
|
NO_FITTING = 0x19,
|
||||||
|
SPACE = 0x1A,
|
||||||
|
COMMON_CHARACTER = 0x20,
|
||||||
|
SPECIAL_CHARACTER = 0x40,
|
||||||
|
CUSTOM_NULL = 0x99,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
vector<tuple<TEXT_OP_CODE, vector<u16>>> OPCODES;
|
||||||
|
unordered_map<TEXT_OP_CODE, pair<string, string>> CODES = {
|
||||||
|
{TEXT_OP_CODE::CENTERED, pair<string, string>("CENTER", "")},
|
||||||
|
{TEXT_OP_CODE::RESET_CENTERED, pair<string, string>("/CENTER", "")},
|
||||||
|
{TEXT_OP_CODE::CLEAR_COLOR, pair<string, string>("/COLOR", "")},
|
||||||
|
{TEXT_OP_CODE::COLOR, pair<string, string>("COLOR", "bbb")},
|
||||||
|
{TEXT_OP_CODE::END, pair<string, string>("END", "")},
|
||||||
|
{TEXT_OP_CODE::FITTING, pair<string, string>("FIT", "")},
|
||||||
|
{TEXT_OP_CODE::KERNING, pair<string, string>("KERN", "")},
|
||||||
|
{TEXT_OP_CODE::LEFT_ALIGNED, pair<string, string>("LEFT", "")},
|
||||||
|
{TEXT_OP_CODE::LINE_BREAK, pair<string, string>("BR", "")},
|
||||||
|
{TEXT_OP_CODE::NO_FITTING, pair<string, string>("/FIT", "")},
|
||||||
|
{TEXT_OP_CODE::NO_KERNING, pair<string, string>("/KERN", "")},
|
||||||
|
{TEXT_OP_CODE::OFFSET, pair<string, string>("OFFSET", "ss")},
|
||||||
|
{TEXT_OP_CODE::RESET, pair<string, string>("RESET", "")},
|
||||||
|
{TEXT_OP_CODE::RESET_LEFT_ALIGN, pair<string, string>("/LEFT", "")},
|
||||||
|
{TEXT_OP_CODE::RESET_RIGHT_ALIGN, pair<string, string>("/RIGHT", "")},
|
||||||
|
{TEXT_OP_CODE::RESET_SCALING, pair<string, string>("/SCALE", "")},
|
||||||
|
{TEXT_OP_CODE::RESET_TEXTBOX, pair<string, string>("/TEXTBOX", "")},
|
||||||
|
{TEXT_OP_CODE::RIGHT_ALIGNED, pair<string, string>("/RIGHT", "")},
|
||||||
|
{TEXT_OP_CODE::SCALING, pair<string, string>("SCALE", "bbbb")},
|
||||||
|
{TEXT_OP_CODE::SET_TEXTBOX, pair<string, string>("TEXTBOX", "ss")},
|
||||||
|
{TEXT_OP_CODE::UNKNOWN_02, pair<string, string>("UNK02", "")},
|
||||||
|
{TEXT_OP_CODE::UNKNOWN_04, pair<string, string>("UNK04", "")},
|
||||||
|
{TEXT_OP_CODE::UNKNOWN_05, pair<string, string>("UNK05", "s")},
|
||||||
|
{TEXT_OP_CODE::UNKNOWN_06, pair<string, string>("UNK06", "ss")},
|
||||||
|
{TEXT_OP_CODE::UNKNOWN_08, pair<string, string>("UNK08", "")},
|
||||||
|
{TEXT_OP_CODE::UNKNOWN_09, pair<string, string>("UNK09", "")},
|
||||||
|
{TEXT_OP_CODE::SPACE, pair<string, string>("S", "")},
|
||||||
|
};
|
||||||
|
|
||||||
|
pair<TEXT_OP_CODE, pair<string, string>> findCodeKey(string p)
|
||||||
|
{
|
||||||
|
unordered_map<TEXT_OP_CODE, pair<string, string>>::iterator it;
|
||||||
|
|
||||||
|
for (it = CODES.begin(); it != CODES.end(); it++)
|
||||||
|
{
|
||||||
|
if (it->second.first == p)
|
||||||
|
{
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pair<TEXT_OP_CODE, pair<string, string>>(TEXT_OP_CODE::CUSTOM_NULL,
|
||||||
|
pair<string, string>("", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<tuple<TEXT_OP_CODE, vector<u16>>> DeserializeCodes(vector<u8> data)
|
||||||
|
{
|
||||||
|
vector<tuple<TEXT_OP_CODE, vector<u16>>> d = vector<tuple<TEXT_OP_CODE, vector<u16>>>();
|
||||||
|
|
||||||
|
for (int i = 0; i < data.size();)
|
||||||
|
{
|
||||||
|
auto opcode = (TEXT_OP_CODE)data[i++];
|
||||||
|
vector<u16> param = vector<u16>(0);
|
||||||
|
|
||||||
|
int textCode = (u8)opcode;
|
||||||
|
|
||||||
|
if ((textCode >> 4) == 2)
|
||||||
|
param = vector<u16>{(u16)(((textCode << 8) | (data[i++] & 0xFF)) & 0xFFF)};
|
||||||
|
else if ((textCode >> 4) == 4)
|
||||||
|
param = vector<u16>{(u16)(((textCode << 8) | (data[i++] & 0xFF)) & 0xFFF)};
|
||||||
|
else if (!CODES.count(opcode))
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(SLIPPI, "Opcode Not Supported!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pair<string, string> code = CODES[opcode];
|
||||||
|
auto p = code.second.c_str();
|
||||||
|
param = vector<u16>(strlen(p));
|
||||||
|
for (int j = 0; j < param.size(); j++)
|
||||||
|
{
|
||||||
|
switch (p[j])
|
||||||
|
{
|
||||||
|
case 'b':
|
||||||
|
param[j] = (u16)(data[i++] & 0xFF);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
param[j] = (u16)(((data[i++] & 0xFF) << 8) | (data[i++] & 0xFF));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pair<TEXT_OP_CODE, vector<u16>> c = pair<TEXT_OP_CODE, vector<u16>>(opcode, param);
|
||||||
|
d.push_back(c);
|
||||||
|
|
||||||
|
if (opcode == TEXT_OP_CODE::END)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
|
||||||
|
// trim from start (in place)
|
||||||
|
static inline void ltrim(std::string& s)
|
||||||
|
{
|
||||||
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim from end (in place)
|
||||||
|
static inline void rtrim(std::string& s)
|
||||||
|
{
|
||||||
|
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(),
|
||||||
|
s.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim from both ends (in place)
|
||||||
|
static inline void trim(std::string& s)
|
||||||
|
{
|
||||||
|
ltrim(s);
|
||||||
|
rtrim(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<string> split(const string& str, const string& delim)
|
||||||
|
{
|
||||||
|
vector<string> tokens;
|
||||||
|
size_t prev = 0, pos = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pos = str.find(delim, prev);
|
||||||
|
if (pos == string::npos)
|
||||||
|
pos = str.length();
|
||||||
|
string token = str.substr(prev, pos - prev);
|
||||||
|
if (!token.empty())
|
||||||
|
tokens.push_back(token);
|
||||||
|
prev = pos + delim.length();
|
||||||
|
} while (pos < str.length() && prev < str.length());
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
// region CharMAPS
|
||||||
|
int CHAR_MAP[287] = {
|
||||||
|
'0',
|
||||||
|
'1',
|
||||||
|
'2',
|
||||||
|
'3',
|
||||||
|
'4',
|
||||||
|
'5',
|
||||||
|
'6',
|
||||||
|
'7',
|
||||||
|
'8',
|
||||||
|
'9',
|
||||||
|
'A',
|
||||||
|
'B',
|
||||||
|
'C',
|
||||||
|
'D',
|
||||||
|
'E',
|
||||||
|
'F',
|
||||||
|
'G',
|
||||||
|
'H',
|
||||||
|
'I',
|
||||||
|
'J',
|
||||||
|
'K',
|
||||||
|
'L',
|
||||||
|
'M',
|
||||||
|
'N',
|
||||||
|
'O',
|
||||||
|
'P',
|
||||||
|
'Q',
|
||||||
|
'R',
|
||||||
|
'S',
|
||||||
|
'T',
|
||||||
|
'U',
|
||||||
|
'V',
|
||||||
|
'W',
|
||||||
|
'X',
|
||||||
|
'Y',
|
||||||
|
'Z',
|
||||||
|
'a',
|
||||||
|
'b',
|
||||||
|
'c',
|
||||||
|
'd',
|
||||||
|
'e',
|
||||||
|
'f',
|
||||||
|
'g',
|
||||||
|
'h',
|
||||||
|
'i',
|
||||||
|
'j',
|
||||||
|
'k',
|
||||||
|
'l',
|
||||||
|
'm',
|
||||||
|
'n',
|
||||||
|
'o',
|
||||||
|
'p',
|
||||||
|
'q',
|
||||||
|
'r',
|
||||||
|
's',
|
||||||
|
't',
|
||||||
|
'u',
|
||||||
|
'v',
|
||||||
|
'w',
|
||||||
|
'x',
|
||||||
|
0x0079 /*'y'*/,
|
||||||
|
0x007a /*'z'*/,
|
||||||
|
0x3041 /*'ぁ'*/,
|
||||||
|
0x3042 /*'あ'*/,
|
||||||
|
0x3043 /*'ぃ'*/,
|
||||||
|
0x3044 /*'い'*/,
|
||||||
|
0x3045 /*'ぅ'*/,
|
||||||
|
0x3046 /*'う'*/,
|
||||||
|
0x3047 /*'ぇ'*/,
|
||||||
|
0x3048 /*'え'*/,
|
||||||
|
0x3049 /*'ぉ'*/,
|
||||||
|
0x304a /*'お'*/,
|
||||||
|
0x304b /*'か'*/,
|
||||||
|
0x304c /*'が'*/,
|
||||||
|
0x304d /*'き'*/,
|
||||||
|
0x304e /*'ぎ'*/,
|
||||||
|
0x304f /*'く'*/,
|
||||||
|
0x3050 /*'ぐ'*/,
|
||||||
|
0x3051 /*'け'*/,
|
||||||
|
0x3052 /*'げ'*/,
|
||||||
|
0x3053 /*'こ'*/,
|
||||||
|
0x3054 /*'ご'*/,
|
||||||
|
0x3055 /*'さ'*/,
|
||||||
|
0x3056 /*'ざ'*/,
|
||||||
|
0x3057 /*'し'*/,
|
||||||
|
0x3058 /*'じ'*/,
|
||||||
|
0x3059 /*'す'*/,
|
||||||
|
0x305a /*'ず'*/,
|
||||||
|
0x305b /*'せ'*/,
|
||||||
|
0x305c /*'ぜ'*/,
|
||||||
|
0x305d /*'そ'*/,
|
||||||
|
0x305e /*'ぞ'*/,
|
||||||
|
0x305f /*'た'*/,
|
||||||
|
0x3060 /*'だ'*/,
|
||||||
|
0x3061 /*'ち'*/,
|
||||||
|
0x3062 /*'ぢ'*/,
|
||||||
|
0x3063 /*'っ'*/,
|
||||||
|
0x3064 /*'つ'*/,
|
||||||
|
0x3065 /*'づ'*/,
|
||||||
|
0x3066 /*'て'*/,
|
||||||
|
0x3067 /*'で'*/,
|
||||||
|
0x3068 /*'と'*/,
|
||||||
|
0x3069 /*'ど'*/,
|
||||||
|
0x306a /*'な'*/,
|
||||||
|
0x306b /*'に'*/,
|
||||||
|
0x306c /*'ぬ'*/,
|
||||||
|
0x306d /*'ね'*/,
|
||||||
|
0x306e /*'の'*/,
|
||||||
|
0x306f /*'は'*/,
|
||||||
|
0x3070 /*'ば'*/,
|
||||||
|
0x3071 /*'ぱ'*/,
|
||||||
|
0x3072 /*'ひ'*/,
|
||||||
|
0x3073 /*'び'*/,
|
||||||
|
0x3074 /*'ぴ'*/,
|
||||||
|
0x3075 /*'ふ'*/,
|
||||||
|
0x3076 /*'ぶ'*/,
|
||||||
|
0x3077 /*'ぷ'*/,
|
||||||
|
0x3078 /*'へ'*/,
|
||||||
|
0x3079 /*'べ'*/,
|
||||||
|
0x307a /*'ぺ'*/,
|
||||||
|
0x307b /*'ほ'*/,
|
||||||
|
0x307c /*'ぼ'*/,
|
||||||
|
0x307d /*'ぽ'*/,
|
||||||
|
0x307e /*'ま'*/,
|
||||||
|
0x307f /*'み'*/,
|
||||||
|
0x3080 /*'む'*/,
|
||||||
|
0x3081 /*'め'*/,
|
||||||
|
0x3082 /*'も'*/,
|
||||||
|
0x3083 /*'ゃ'*/,
|
||||||
|
0x3084 /*'や'*/,
|
||||||
|
0x3085 /*'ゅ'*/,
|
||||||
|
0x3086 /*'ゆ'*/,
|
||||||
|
0x3087 /*'ょ'*/,
|
||||||
|
0x3088 /*'よ'*/,
|
||||||
|
0x3089 /*'ら'*/,
|
||||||
|
0x308a /*'り'*/,
|
||||||
|
0x308b /*'る'*/,
|
||||||
|
0x308c /*'れ'*/,
|
||||||
|
0x308d /*'ろ'*/,
|
||||||
|
0x308e /*'ゎ'*/,
|
||||||
|
0x308f /*'わ'*/,
|
||||||
|
0x3092 /*'を'*/,
|
||||||
|
0x3093 /*'ん'*/,
|
||||||
|
0x30a1 /*'ァ'*/,
|
||||||
|
0x30a2 /*'ア'*/,
|
||||||
|
0x30a3 /*'ィ'*/,
|
||||||
|
0x30a4 /*'イ'*/,
|
||||||
|
0x30a5 /*'ゥ'*/,
|
||||||
|
0x30a6 /*'ウ'*/,
|
||||||
|
0x30a7 /*'ェ'*/,
|
||||||
|
0x30a8 /*'エ'*/,
|
||||||
|
0x30a9 /*'ォ'*/,
|
||||||
|
0x30aa /*'オ'*/,
|
||||||
|
0x30ab /*'カ'*/,
|
||||||
|
0x30ac /*'ガ'*/,
|
||||||
|
0x30ad /*'キ'*/,
|
||||||
|
0x30ae /*'ギ'*/,
|
||||||
|
0x30af /*'ク'*/,
|
||||||
|
0x30b0 /*'グ'*/,
|
||||||
|
0x30b1 /*'ケ'*/,
|
||||||
|
0x30b2 /*'ゲ'*/,
|
||||||
|
0x30b3 /*'コ'*/,
|
||||||
|
0x30b4 /*'ゴ'*/,
|
||||||
|
0x30b5 /*'サ'*/,
|
||||||
|
0x30b6 /*'ザ'*/,
|
||||||
|
0x30b7 /*'シ'*/,
|
||||||
|
0x30b8 /*'ジ'*/,
|
||||||
|
0x30b9 /*'ス'*/,
|
||||||
|
0x30ba /*'ズ'*/,
|
||||||
|
0x30bb /*'セ'*/,
|
||||||
|
0x30bc /*'ゼ'*/,
|
||||||
|
0x30bd /*'ソ'*/,
|
||||||
|
0x30be /*'ゾ'*/,
|
||||||
|
0x30bf /*'タ'*/,
|
||||||
|
0x30c0 /*'ダ'*/,
|
||||||
|
0x30c1 /*'チ'*/,
|
||||||
|
0x30c2 /*'ヂ'*/,
|
||||||
|
0x30c3 /*'ッ'*/,
|
||||||
|
0x30c4 /*'ツ'*/,
|
||||||
|
0x30c5 /*'ヅ'*/,
|
||||||
|
0x30c6 /*'テ'*/,
|
||||||
|
0x30c7 /*'デ'*/,
|
||||||
|
0x30c8 /*'ト'*/,
|
||||||
|
0x30c9 /*'ド'*/,
|
||||||
|
0x30ca /*'ナ'*/,
|
||||||
|
0x30cb /*'ニ'*/,
|
||||||
|
0x30cc /*'ヌ'*/,
|
||||||
|
0x30cd /*'ネ'*/,
|
||||||
|
0x30ce /*'ノ'*/,
|
||||||
|
0x30cf /*'ハ'*/,
|
||||||
|
0x30d0 /*'バ'*/,
|
||||||
|
0x30d1 /*'パ'*/,
|
||||||
|
0x30d2 /*'ヒ'*/,
|
||||||
|
0x30d3 /*'ビ'*/,
|
||||||
|
0x30d4 /*'ピ'*/,
|
||||||
|
0x30d5 /*'フ'*/,
|
||||||
|
0x30d6 /*'ブ'*/,
|
||||||
|
0x30d7 /*'プ'*/,
|
||||||
|
0x30d8 /*'ヘ'*/,
|
||||||
|
0x30d9 /*'ベ'*/,
|
||||||
|
0x30da /*'ペ'*/,
|
||||||
|
0x30db /*'ホ'*/,
|
||||||
|
0x30dc /*'ボ'*/,
|
||||||
|
0x30dd /*'ポ'*/,
|
||||||
|
0x30de /*'マ'*/,
|
||||||
|
0x30df /*'ミ'*/,
|
||||||
|
0x30e0 /*'ム'*/,
|
||||||
|
0x30e1 /*'メ'*/,
|
||||||
|
0x30e2 /*'モ'*/,
|
||||||
|
0x30e3 /*'ャ'*/,
|
||||||
|
0x30e4 /*'ヤ'*/,
|
||||||
|
0x30e5 /*'ュ'*/,
|
||||||
|
0x30e6 /*'ユ'*/,
|
||||||
|
0x30e7 /*'ョ'*/,
|
||||||
|
0x30e8 /*'ヨ'*/,
|
||||||
|
0x30e9 /*'ラ'*/,
|
||||||
|
0x30ea /*'リ'*/,
|
||||||
|
0x30eb /*'ル'*/,
|
||||||
|
0x30ec /*'レ'*/,
|
||||||
|
0x30ed /*'ロ'*/,
|
||||||
|
0x30ee /*'ヮ'*/,
|
||||||
|
0x30ef /*'ワ'*/,
|
||||||
|
0x30f2 /*'ヲ'*/,
|
||||||
|
0x30f3 /*'ン'*/,
|
||||||
|
0x30f4 /*'ヴ'*/,
|
||||||
|
0x30f5 /*'ヵ'*/,
|
||||||
|
0x30f6 /*'ヶ'*/,
|
||||||
|
0x3000 /*' '*/,
|
||||||
|
0x3001 /*'、'*/,
|
||||||
|
0x3002 /*'。'*/,
|
||||||
|
0x002c /*','*/,
|
||||||
|
0x002e /*'.'*/,
|
||||||
|
0x2022 /*'•'*/,
|
||||||
|
0x002c /*','*/,
|
||||||
|
0x003b /*';'*/,
|
||||||
|
0x003f /*'?'*/,
|
||||||
|
0x0021 /*'!'*/,
|
||||||
|
0x005e /*'^'*/,
|
||||||
|
0x005f /*'_'*/,
|
||||||
|
0x2014 /*'—'*/,
|
||||||
|
0x002f /*'/'*/,
|
||||||
|
0x007e /*'~'*/,
|
||||||
|
0x007c /*'|'*/,
|
||||||
|
0x0027 /*'\''*/,
|
||||||
|
0x0022 /*'"'*/,
|
||||||
|
0x0028 /*'('*/,
|
||||||
|
0x0029 /*')'*/,
|
||||||
|
0x005b /*'['*/,
|
||||||
|
0x005d /*']'*/,
|
||||||
|
0x007b /*'{'*/,
|
||||||
|
0x007d /*'}'*/,
|
||||||
|
0x002b /*'+'*/,
|
||||||
|
'-',
|
||||||
|
0x00d7 /*'×'*/,
|
||||||
|
0x003d /*'='*/,
|
||||||
|
0x003c /*'<'*/,
|
||||||
|
0x003e /*'>'*/,
|
||||||
|
0x00a5 /*'¥'*/,
|
||||||
|
0x0024 /*'$'*/,
|
||||||
|
0x0025 /*'%'*/,
|
||||||
|
0x0023 /*'#'*/,
|
||||||
|
0x0026 /*'&'*/,
|
||||||
|
0x002a /*'*'*/,
|
||||||
|
0x0040 /*'@'*/,
|
||||||
|
0x6271 /*'扱'*/,
|
||||||
|
0x62bc /*'押'*/,
|
||||||
|
0x8ecd /*'軍'*/,
|
||||||
|
0x6e90 /*'源'*/,
|
||||||
|
0x500b /*'個'*/,
|
||||||
|
0x8fbc /*'込'*/,
|
||||||
|
0x6307 /*'指'*/,
|
||||||
|
0x793a /*'示'*/,
|
||||||
|
0x53d6 /*'取'*/,
|
||||||
|
0x66f8 /*'書'*/,
|
||||||
|
0x8a73 /*'詳'*/,
|
||||||
|
0x4eba /*'人'*/,
|
||||||
|
0x751f /*'生'*/,
|
||||||
|
0x8aac /*'説'*/,
|
||||||
|
0x4f53 /*'体'*/,
|
||||||
|
0x56e3 /*'団'*/,
|
||||||
|
0x96fb /*'電'*/,
|
||||||
|
0x8aad /*'読'*/,
|
||||||
|
0x767a /*'発'*/,
|
||||||
|
0x629c /*'抜'*/,
|
||||||
|
0x9591 /*'閑'*/,
|
||||||
|
0x672c /*'本'*/,
|
||||||
|
0x660e /*'明'*/,
|
||||||
|
};
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue