Convert tabs to spaces
This commit is contained in:
parent
d20cc3ee1c
commit
b534359325
310
source/app.d
310
source/app.d
|
@ -15,100 +15,100 @@ import config;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
auto router = new URLRouter;
|
auto router = new URLRouter;
|
||||||
router.get("*", reverseProxyRequest(serverHost, serverPort));
|
router.get("*", reverseProxyRequest(serverHost, serverPort));
|
||||||
router.post("/api/v1/*", &onAPIRequest);
|
router.post("/api/v1/*", &onAPIRequest);
|
||||||
|
|
||||||
auto settings = new HTTPServerSettings;
|
auto settings = new HTTPServerSettings;
|
||||||
settings.port = proxyPortNumber;
|
settings.port = proxyPortNumber;
|
||||||
settings.options = HTTPServerOption.parseURL | HTTPServerOption.errorStackTraces;
|
settings.options = HTTPServerOption.parseURL | HTTPServerOption.errorStackTraces;
|
||||||
listenHTTP(settings, router);
|
listenHTTP(settings, router);
|
||||||
|
|
||||||
runApplication();
|
runApplication();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onAPIRequest(HTTPServerRequest request, HTTPServerResponse response)
|
void onAPIRequest(HTTPServerRequest request, HTTPServerResponse response)
|
||||||
{
|
{
|
||||||
auto apiEndpoint = request.path.split("/api/v1")[1];
|
auto apiEndpoint = request.path.split("/api/v1")[1];
|
||||||
auto nonce = request.headers["auth_nonce"];
|
auto nonce = request.headers["auth_nonce"];
|
||||||
|
|
||||||
auto requestBody = request.bodyReader.readAll();
|
auto requestBody = request.bodyReader.readAll();
|
||||||
auto requestJson = getRequestJson(requestBody, apiEndpoint, nonce);
|
auto requestJson = getRequestJson(requestBody, apiEndpoint, nonce);
|
||||||
handleRequest(apiEndpoint, requestJson);
|
handleRequest(apiEndpoint, requestJson);
|
||||||
|
|
||||||
//TODO: Allow request editing (requires recalculation of signature)
|
//TODO: Allow request editing (requires recalculation of signature)
|
||||||
//NOTE: This would not be a very useful feature, so this might be removed later.
|
//NOTE: This would not be a very useful feature, so this might be removed later.
|
||||||
// One thing it would be useful for is creating a bot for keeping track of API changes.
|
// One thing it would be useful for is creating a bot for keeping track of API changes.
|
||||||
// This would also require quite a bit of refactoring however.
|
// This would also require quite a bit of refactoring however.
|
||||||
auto apiResponse = sendRequest(apiEndpoint, request.headers.dup, requestBody);
|
auto apiResponse = sendRequest(apiEndpoint, request.headers.dup, requestBody);
|
||||||
|
|
||||||
auto responseBody = apiResponse.bodyReader.readAll();
|
auto responseBody = apiResponse.bodyReader.readAll();
|
||||||
auto responseJson = getResponseJson(responseBody, apiEndpoint, nonce);
|
auto responseJson = getResponseJson(responseBody, apiEndpoint, nonce);
|
||||||
|
|
||||||
auto finalResponseJson = handleResponse(apiEndpoint, responseJson);
|
auto finalResponseJson = handleResponse(apiEndpoint, responseJson);
|
||||||
auto finalResponseBody = constructResponseBody(apiEndpoint, finalResponseJson, nonce);
|
auto finalResponseBody = constructResponseBody(apiEndpoint, finalResponseJson, nonce);
|
||||||
|
|
||||||
sendResponse(response, apiResponse, finalResponseBody);
|
sendResponse(response, apiResponse, finalResponseBody);
|
||||||
|
|
||||||
import std.stdio : writeln;
|
import std.stdio : writeln;
|
||||||
writeln(apiEndpoint);
|
writeln(apiEndpoint);
|
||||||
|
|
||||||
import std.file : append;
|
import std.file : append;
|
||||||
struct LogEntry
|
struct LogEntry
|
||||||
{
|
{
|
||||||
string endpoint;
|
string endpoint;
|
||||||
Json request;
|
Json request;
|
||||||
Json response;
|
Json response;
|
||||||
}
|
}
|
||||||
append("api.log", LogEntry(apiEndpoint, requestJson, finalResponseJson).serializeToJson.toPrettyString ~ "\n\n");
|
append("api.log", LogEntry(apiEndpoint, requestJson, finalResponseJson).serializeToJson.toPrettyString ~ "\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
Json getRequestJson(ubyte[] input, string endpoint, string nonce)
|
Json getRequestJson(ubyte[] input, string endpoint, string nonce)
|
||||||
{
|
{
|
||||||
auto originalRequestPipe = Pipe
|
auto originalRequestPipe = Pipe
|
||||||
(
|
(
|
||||||
new Base64Decoder,
|
new Base64Decoder,
|
||||||
getCipher
|
getCipher
|
||||||
(
|
(
|
||||||
cipherName,
|
cipherName,
|
||||||
SymmetricKey((cast(ubyte[]) keyString).ptr, keyString.length),
|
SymmetricKey((cast(ubyte[]) keyString).ptr, keyString.length),
|
||||||
InitializationVector((cast(ubyte[]) nonce).ptr, nonce.length),
|
InitializationVector((cast(ubyte[]) nonce).ptr, nonce.length),
|
||||||
DECRYPTION
|
DECRYPTION
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
originalRequestPipe.processMsg(input.ptr, input.length);
|
originalRequestPipe.processMsg(input.ptr, input.length);
|
||||||
|
|
||||||
auto requestJsonString = originalRequestPipe.toString;
|
auto requestJsonString = originalRequestPipe.toString;
|
||||||
return requestJsonString.parseJson;
|
return requestJsonString.parseJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
Json getResponseJson(ubyte[] input, string endpoint, string nonce)
|
Json getResponseJson(ubyte[] input, string endpoint, string nonce)
|
||||||
{
|
{
|
||||||
import std.zlib : uncompress;
|
import std.zlib : uncompress;
|
||||||
|
|
||||||
switch(endpoint)
|
switch(endpoint)
|
||||||
{
|
{
|
||||||
case "/config/getGameConfig":
|
case "/config/getGameConfig":
|
||||||
return getRequestJson(input, endpoint, nonce);
|
return getRequestJson(input, endpoint, nonce);
|
||||||
case "/master/getMaster":
|
case "/master/getMaster":
|
||||||
auto decompressedInput = cast(ubyte[])uncompress(input); //TODO: Use pipe instead (how?)
|
auto decompressedInput = cast(ubyte[])uncompress(input); //TODO: Use pipe instead (how?)
|
||||||
|
|
||||||
auto responseJsonString = cast(string) decompressedInput;
|
auto responseJsonString = cast(string) decompressedInput;
|
||||||
return responseJsonString.parseJson;
|
return responseJsonString.parseJson;
|
||||||
default:
|
default:
|
||||||
auto decompressedInput = cast(ubyte[])uncompress(input); //TODO: Use pipe instead (how?)
|
auto decompressedInput = cast(ubyte[])uncompress(input); //TODO: Use pipe instead (how?)
|
||||||
|
|
||||||
auto responsePipe = Pipe
|
auto responsePipe = Pipe
|
||||||
(
|
(
|
||||||
new Base64Decoder
|
new Base64Decoder
|
||||||
);
|
);
|
||||||
|
|
||||||
responsePipe.processMsg(decompressedInput.ptr, decompressedInput.length);
|
responsePipe.processMsg(decompressedInput.ptr, decompressedInput.length);
|
||||||
|
|
||||||
auto responseJsonString = responsePipe.toString;
|
auto responseJsonString = responsePipe.toString;
|
||||||
return responseJsonString.parseJson;
|
return responseJsonString.parseJson;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleRequest(string endpoint, Json json)
|
void handleRequest(string endpoint, Json json)
|
||||||
|
@ -118,127 +118,127 @@ void handleRequest(string endpoint, Json json)
|
||||||
|
|
||||||
Json handleResponse(string endpoint, Json json)
|
Json handleResponse(string endpoint, Json json)
|
||||||
{
|
{
|
||||||
if(endpoint == "/master/getMaster")
|
if(endpoint == "/master/getMaster")
|
||||||
{
|
{
|
||||||
import models.master;
|
import models.master;
|
||||||
auto getMasterResponse = json.deserializeJson!GetMasterResponse;
|
auto getMasterResponse = json.deserializeJson!GetMasterResponse;
|
||||||
|
|
||||||
import dataMixins : applyMasterTranslation;
|
import dataMixins : applyMasterTranslation;
|
||||||
|
|
||||||
mixin(applyMasterTranslation!("Character", 0,
|
mixin(applyMasterTranslation!("Character", 0,
|
||||||
5, "characterNames"));
|
5, "characterNames"));
|
||||||
|
|
||||||
mixin(applyMasterTranslation!("CharacterSkill", 0,
|
mixin(applyMasterTranslation!("CharacterSkill", 0,
|
||||||
1, "skillNames",
|
1, "skillNames",
|
||||||
6, "skillDescriptions"));
|
6, "skillDescriptions"));
|
||||||
|
|
||||||
mixin(applyMasterTranslation!("Stage", 0,
|
mixin(applyMasterTranslation!("Stage", 0,
|
||||||
1, "stageNames"));
|
1, "stageNames"));
|
||||||
|
|
||||||
//TODO: Figure out a way to find the wrong ones
|
//TODO: Figure out a way to find the wrong ones
|
||||||
mixin(applyMasterTranslation!("Mission", 0,
|
mixin(applyMasterTranslation!("Mission", 0,
|
||||||
1, "missionNames",
|
1, "missionNames",
|
||||||
2, "missionDescriptions",
|
2, "missionDescriptions",
|
||||||
3, "missionRewards"));
|
3, "missionRewards"));
|
||||||
|
|
||||||
mixin(applyMasterTranslation!("Dungeon", 10,
|
mixin(applyMasterTranslation!("Dungeon", 10,
|
||||||
12, "dungeonNames"));
|
12, "dungeonNames"));
|
||||||
|
|
||||||
mixin(applyMasterTranslation!("Guest", 0,
|
mixin(applyMasterTranslation!("Guest", 0,
|
||||||
1, "guestPartyNames"));
|
1, "guestPartyNames"));
|
||||||
|
|
||||||
mixin(applyMasterTranslation!("Item", 0,
|
mixin(applyMasterTranslation!("Item", 0,
|
||||||
1, "itemNames"));
|
1, "itemNames"));
|
||||||
|
|
||||||
mixin(applyMasterTranslation!("WorldMap", 0,
|
mixin(applyMasterTranslation!("WorldMap", 0,
|
||||||
3, "worldMapLocationNames",
|
3, "worldMapLocationNames",
|
||||||
4, "worldMapLocationCaptions",
|
4, "worldMapLocationCaptions",
|
||||||
5, "worldMapLocationDescriptions"));
|
5, "worldMapLocationDescriptions"));
|
||||||
|
|
||||||
mixin(applyMasterTranslation!("CharacterTextResource", 0,
|
mixin(applyMasterTranslation!("CharacterTextResource", 0,
|
||||||
3, "characterTextResource"));
|
3, "characterTextResource"));
|
||||||
|
|
||||||
mixin(applyMasterTranslation!("CharacterLeaderSkill", 0,
|
mixin(applyMasterTranslation!("CharacterLeaderSkill", 0,
|
||||||
1, "characterLeaderSkillNames",
|
1, "characterLeaderSkillNames",
|
||||||
14, "characterLeaderSkillDescriptions"));
|
14, "characterLeaderSkillDescriptions"));
|
||||||
|
|
||||||
mixin(applyMasterTranslation!("CharacterBook", 0,
|
mixin(applyMasterTranslation!("CharacterBook", 0,
|
||||||
5, "characterBookFlowerLanguage"));
|
5, "characterBookFlowerLanguage"));
|
||||||
|
|
||||||
mixin(applyMasterTranslation!("CharacterCategory", 0,
|
mixin(applyMasterTranslation!("CharacterCategory", 0,
|
||||||
1, "characterCategories"));
|
1, "characterCategories"));
|
||||||
|
|
||||||
return getMasterResponse.serializeToJson;
|
return getMasterResponse.serializeToJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
ubyte[] constructResponseBody(string endpoint, Json json, string nonce)
|
ubyte[] constructResponseBody(string endpoint, Json json, string nonce)
|
||||||
{
|
{
|
||||||
import std.zlib : compress;
|
import std.zlib : compress;
|
||||||
|
|
||||||
auto jsonStringBytes = cast(ubyte[]) json.toString;
|
auto jsonStringBytes = cast(ubyte[]) json.toString;
|
||||||
|
|
||||||
switch(endpoint)
|
switch(endpoint)
|
||||||
{
|
{
|
||||||
case "/config/getGameConfig":
|
case "/config/getGameConfig":
|
||||||
auto responsePipe = Pipe
|
auto responsePipe = Pipe
|
||||||
(
|
(
|
||||||
getCipher
|
getCipher
|
||||||
(
|
(
|
||||||
cipherName,
|
cipherName,
|
||||||
SymmetricKey((cast(ubyte[]) keyString).ptr, keyString.length),
|
SymmetricKey((cast(ubyte[]) keyString).ptr, keyString.length),
|
||||||
InitializationVector((cast(ubyte[]) nonce).ptr, nonce.length),
|
InitializationVector((cast(ubyte[]) nonce).ptr, nonce.length),
|
||||||
ENCRYPTION
|
ENCRYPTION
|
||||||
),
|
),
|
||||||
new Base64Encoder
|
new Base64Encoder
|
||||||
);
|
);
|
||||||
|
|
||||||
//TODO: Refactor this
|
//TODO: Refactor this
|
||||||
if(jsonStringBytes.length % 16 != 0)
|
if(jsonStringBytes.length % 16 != 0)
|
||||||
{
|
{
|
||||||
jsonStringBytes.length += 16 - jsonStringBytes.length % 16;
|
jsonStringBytes.length += 16 - jsonStringBytes.length % 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
responsePipe.processMsg(jsonStringBytes.ptr, jsonStringBytes.length);
|
responsePipe.processMsg(jsonStringBytes.ptr, jsonStringBytes.length);
|
||||||
|
|
||||||
return cast(ubyte[]) responsePipe.toString;
|
return cast(ubyte[]) responsePipe.toString;
|
||||||
case "/master/getMaster":
|
case "/master/getMaster":
|
||||||
return compress(jsonStringBytes); //TODO: Use pipe instead (how?)
|
return compress(jsonStringBytes); //TODO: Use pipe instead (how?)
|
||||||
default:
|
default:
|
||||||
auto responsePipe = Pipe
|
auto responsePipe = Pipe
|
||||||
(
|
(
|
||||||
new Base64Encoder
|
new Base64Encoder
|
||||||
);
|
);
|
||||||
|
|
||||||
responsePipe.processMsg(jsonStringBytes.ptr, jsonStringBytes.length);
|
responsePipe.processMsg(jsonStringBytes.ptr, jsonStringBytes.length);
|
||||||
|
|
||||||
return compress(responsePipe.toString);
|
return compress(responsePipe.toString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTPClientResponse sendRequest(string endpoint, InetHeaderMap headers, ubyte[] requestBody)
|
HTTPClientResponse sendRequest(string endpoint, InetHeaderMap headers, ubyte[] requestBody)
|
||||||
{
|
{
|
||||||
return requestHTTP("http://" ~ serverHost ~ "/api/v1" ~ endpoint,
|
return requestHTTP("http://" ~ serverHost ~ "/api/v1" ~ endpoint,
|
||||||
(scope HTTPClientRequest r)
|
(scope HTTPClientRequest r)
|
||||||
{
|
{
|
||||||
r.method = HTTPMethod.POST;
|
r.method = HTTPMethod.POST;
|
||||||
r.headers = headers.dup;
|
r.headers = headers.dup;
|
||||||
r.writeBody(requestBody, r.headers["Content-Type"]);
|
r.writeBody(requestBody, r.headers["Content-Type"]);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendResponse(HTTPServerResponse response, HTTPClientResponse apiResponse, ubyte[] responseBody)
|
void sendResponse(HTTPServerResponse response, HTTPClientResponse apiResponse, ubyte[] responseBody)
|
||||||
{
|
{
|
||||||
//HACK:This is necessary because of something, but I don't remember what
|
//HACK:This is necessary because of something, but I don't remember what
|
||||||
if("Transfer-Encoding" in apiResponse.headers)
|
if("Transfer-Encoding" in apiResponse.headers)
|
||||||
{
|
{
|
||||||
apiResponse.headers.remove("Transfer-Encoding");
|
apiResponse.headers.remove("Transfer-Encoding");
|
||||||
}
|
}
|
||||||
response.statusCode = apiResponse.statusCode;
|
response.statusCode = apiResponse.statusCode;
|
||||||
response.statusPhrase = apiResponse.statusPhrase;
|
response.statusPhrase = apiResponse.statusPhrase;
|
||||||
response.headers = apiResponse.headers.dup;
|
response.headers = apiResponse.headers.dup;
|
||||||
response.writeBody(responseBody);
|
response.writeBody(responseBody);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,34 +2,34 @@ module dataMixins;
|
||||||
|
|
||||||
template applyMasterTranslation(string Table, uint IdFieldIndex, Translations...)
|
template applyMasterTranslation(string Table, uint IdFieldIndex, Translations...)
|
||||||
{
|
{
|
||||||
static assert(Translations.length >= 2 && Translations.length % 2 == 0);
|
static assert(Translations.length >= 2 && Translations.length % 2 == 0);
|
||||||
|
|
||||||
import std.conv : to;
|
import std.conv : to;
|
||||||
import std.uni : toLower;
|
import std.uni : toLower;
|
||||||
private template getMasterColumnTranslations(Translations...)
|
private template getMasterColumnTranslations(Translations...)
|
||||||
{
|
{
|
||||||
static if(Translations.length > 0)
|
static if(Translations.length > 0)
|
||||||
{
|
{
|
||||||
enum getMasterColumnTranslations = "row[" ~ Translations[0].to!string ~ "] = " ~ Translations[1] ~ "[id]; "
|
enum getMasterColumnTranslations = "row[" ~ Translations[0].to!string ~ "] = " ~ Translations[1] ~ "[id]; "
|
||||||
~ getMasterColumnTranslations!(Translations[2 .. $]);
|
~ getMasterColumnTranslations!(Translations[2 .. $]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
enum getMasterColumnTranslations = "";
|
enum getMasterColumnTranslations = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum applyMasterTranslation = "
|
enum applyMasterTranslation = "
|
||||||
foreach(row; getMasterResponse.master" ~ Table ~ ")
|
foreach(row; getMasterResponse.master" ~ Table ~ ")
|
||||||
{
|
{
|
||||||
import std.conv : to;
|
import std.conv : to;
|
||||||
auto id = row[" ~ IdFieldIndex.to!string ~ "].to!uint;
|
auto id = row[" ~ IdFieldIndex.to!string ~ "].to!uint;
|
||||||
|
|
||||||
import translations." ~ Table[0].toLower.to!string ~ Table[1 .. $] ~ ";
|
import translations." ~ Table[0].toLower.to!string ~ Table[1 .. $] ~ ";
|
||||||
|
|
||||||
if(id in " ~ Translations[1] ~ ")
|
if(id in " ~ Translations[1] ~ ")
|
||||||
{
|
{
|
||||||
" ~ getMasterColumnTranslations!(Translations) ~ "
|
" ~ getMasterColumnTranslations!(Translations) ~ "
|
||||||
}
|
}
|
||||||
}";
|
}";
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,92 +6,92 @@ import std.typecons : Nullable;
|
||||||
|
|
||||||
class GetMasterResponse : Response
|
class GetMasterResponse : Response
|
||||||
{
|
{
|
||||||
Nullable!Base64CSV masterTutorial;
|
Nullable!Base64CSV masterTutorial;
|
||||||
Nullable!Base64CSV masterStory;
|
Nullable!Base64CSV masterStory;
|
||||||
Nullable!Base64CSV masterPanelMission;
|
Nullable!Base64CSV masterPanelMission;
|
||||||
Nullable!Base64CSV masterEquipmentPurificationGroups;
|
Nullable!Base64CSV masterEquipmentPurificationGroups;
|
||||||
Nullable!Base64CSV masterBossAi;
|
Nullable!Base64CSV masterBossAi;
|
||||||
Nullable!Base64CSV masterAlbumDungeon;
|
Nullable!Base64CSV masterAlbumDungeon;
|
||||||
Nullable!Base64CSV masterMissionItem;
|
Nullable!Base64CSV masterMissionItem;
|
||||||
Nullable!Base64CSV masterNavigation;
|
Nullable!Base64CSV masterNavigation;
|
||||||
Nullable!Base64CSV masterCharacterParticular;
|
Nullable!Base64CSV masterCharacterParticular;
|
||||||
Nullable!Base64CSV masterCharacterTrainableLeaderSkill;
|
Nullable!Base64CSV masterCharacterTrainableLeaderSkill;
|
||||||
Nullable!Base64CSV masterDefenseSetting;
|
Nullable!Base64CSV masterDefenseSetting;
|
||||||
Nullable!Base64CSV masterGardenSpecialCharacter;
|
Nullable!Base64CSV masterGardenSpecialCharacter;
|
||||||
Nullable!Base64CSV masterCharacterEquipmentEvolve;
|
Nullable!Base64CSV masterCharacterEquipmentEvolve;
|
||||||
Nullable!Base64CSV masterCharacterSkill;
|
Nullable!Base64CSV masterCharacterSkill;
|
||||||
Nullable!Base64CSV masterCollaboSymphony;
|
Nullable!Base64CSV masterCollaboSymphony;
|
||||||
Nullable!Base64CSV masterCharacterEquipmentLevelGroup;
|
Nullable!Base64CSV masterCharacterEquipmentLevelGroup;
|
||||||
Nullable!Base64CSV masterCharacterQuestItem;
|
Nullable!Base64CSV masterCharacterQuestItem;
|
||||||
Nullable!Base64CSV masterSurvey;
|
Nullable!Base64CSV masterSurvey;
|
||||||
Nullable!Base64CSV masterCharacterMyPagePattern;
|
Nullable!Base64CSV masterCharacterMyPagePattern;
|
||||||
Nullable!Base64CSV masterGift;
|
Nullable!Base64CSV masterGift;
|
||||||
Nullable!Base64CSV masterDungeonRecommendPrioritys;
|
Nullable!Base64CSV masterDungeonRecommendPrioritys;
|
||||||
Nullable!Base64CSV masterAlbumQuestClear;
|
Nullable!Base64CSV masterAlbumQuestClear;
|
||||||
Nullable!Base64CSV masterStageEvaluationItem;
|
Nullable!Base64CSV masterStageEvaluationItem;
|
||||||
Nullable!Base64CSV masterItem;
|
Nullable!Base64CSV masterItem;
|
||||||
Nullable!Base64CSV masterCharacterFlowerings;
|
Nullable!Base64CSV masterCharacterFlowerings;
|
||||||
Nullable!Base64CSV masterPlant;
|
Nullable!Base64CSV masterPlant;
|
||||||
Nullable!Base64CSV masterCharacterTrainableLeaderSkillAcquireCondition;
|
Nullable!Base64CSV masterCharacterTrainableLeaderSkillAcquireCondition;
|
||||||
Nullable!Base64CSV masterEquipmentPurifications;
|
Nullable!Base64CSV masterEquipmentPurifications;
|
||||||
Nullable!Base64CSV masterCharacterEquipment;
|
Nullable!Base64CSV masterCharacterEquipment;
|
||||||
Nullable!Base64CSV masterCharacterTextResource;
|
Nullable!Base64CSV masterCharacterTextResource;
|
||||||
Nullable!Base64CSV masterAlbumTheaterGroup;
|
Nullable!Base64CSV masterAlbumTheaterGroup;
|
||||||
Nullable!Base64CSV masterMission;
|
Nullable!Base64CSV masterMission;
|
||||||
Nullable!Base64CSV masterCharacterMypageVoiceResourceGroup;
|
Nullable!Base64CSV masterCharacterMypageVoiceResourceGroup;
|
||||||
Nullable!Base64CSV masterGuestCharacter;
|
Nullable!Base64CSV masterGuestCharacter;
|
||||||
Nullable!Base64CSV masterCharacterLeaderSkill;
|
Nullable!Base64CSV masterCharacterLeaderSkill;
|
||||||
Nullable!Base64CSV masterCharacterLeaderSkillDescription;
|
Nullable!Base64CSV masterCharacterLeaderSkillDescription;
|
||||||
Nullable!Base64CSV masterCharacterSkinNotExistVoice;
|
Nullable!Base64CSV masterCharacterSkinNotExistVoice;
|
||||||
Nullable!Base64CSV masterStage;
|
Nullable!Base64CSV masterStage;
|
||||||
Nullable!Base64CSV masterCampaignStaminaDungeon;
|
Nullable!Base64CSV masterCampaignStaminaDungeon;
|
||||||
Nullable!Base64CSV masterGardenMakeoverItemShop;
|
Nullable!Base64CSV masterGardenMakeoverItemShop;
|
||||||
Nullable!Base64CSV masterGardenMakeoverItem;
|
Nullable!Base64CSV masterGardenMakeoverItem;
|
||||||
Nullable!Base64CSV masterWhaleHomeBanner;
|
Nullable!Base64CSV masterWhaleHomeBanner;
|
||||||
Nullable!Base64CSV masterSwanBoatRaceGroup;
|
Nullable!Base64CSV masterSwanBoatRaceGroup;
|
||||||
Nullable!Base64CSV masterSynopsis;
|
Nullable!Base64CSV masterSynopsis;
|
||||||
Nullable!Base64CSV masterCharacterLevel;
|
Nullable!Base64CSV masterCharacterLevel;
|
||||||
Nullable!Base64CSV masterPayment;
|
Nullable!Base64CSV masterPayment;
|
||||||
Nullable!Base64CSV masterCharacterBook;
|
Nullable!Base64CSV masterCharacterBook;
|
||||||
Nullable!Base64CSV masterAchievement;
|
Nullable!Base64CSV masterAchievement;
|
||||||
Nullable!Base64CSV masterCharacterCategory;
|
Nullable!Base64CSV masterCharacterCategory;
|
||||||
Nullable!Base64CSV masterAvailableItem;
|
Nullable!Base64CSV masterAvailableItem;
|
||||||
Nullable!Base64CSV masterSwanBoatRaceSchedule;
|
Nullable!Base64CSV masterSwanBoatRaceSchedule;
|
||||||
Nullable!Base64CSV masterCharacterMypageVoiceResource;
|
Nullable!Base64CSV masterCharacterMypageVoiceResource;
|
||||||
Nullable!Base64CSV masterCharacterLevelGroup;
|
Nullable!Base64CSV masterCharacterLevelGroup;
|
||||||
Nullable!Base64CSV masterCharacterQuest;
|
Nullable!Base64CSV masterCharacterQuest;
|
||||||
Nullable!Base64CSV masterCharacterEvolveGroup;
|
Nullable!Base64CSV masterCharacterEvolveGroup;
|
||||||
Nullable!Base64CSV masterCharacterEvolve;
|
Nullable!Base64CSV masterCharacterEvolve;
|
||||||
Nullable!Base64CSV masterKizunaPoint;
|
Nullable!Base64CSV masterKizunaPoint;
|
||||||
Nullable!Base64CSV masterGiftPurifications;
|
Nullable!Base64CSV masterGiftPurifications;
|
||||||
Nullable!Base64CSV masterHomeBgm;
|
Nullable!Base64CSV masterHomeBgm;
|
||||||
Nullable!Base64CSV masterLetter;
|
Nullable!Base64CSV masterLetter;
|
||||||
Nullable!Base64CSV masterPaymentCampaign;
|
Nullable!Base64CSV masterPaymentCampaign;
|
||||||
Nullable!Base64CSV masterLevel;
|
Nullable!Base64CSV masterLevel;
|
||||||
Nullable!Base64CSV masterHomeBanner;
|
Nullable!Base64CSV masterHomeBanner;
|
||||||
Nullable!Base64CSV masterEquipmentPurificationMaterialItems;
|
Nullable!Base64CSV masterEquipmentPurificationMaterialItems;
|
||||||
Nullable!Base64CSV masterGardenPlantFlower;
|
Nullable!Base64CSV masterGardenPlantFlower;
|
||||||
Nullable!Base64CSV masterWorldMap;
|
Nullable!Base64CSV masterWorldMap;
|
||||||
Nullable!Base64CSV masterBoost;
|
Nullable!Base64CSV masterBoost;
|
||||||
Nullable!Base64CSV masterCharacterEquipmentEvolveGroup;
|
Nullable!Base64CSV masterCharacterEquipmentEvolveGroup;
|
||||||
Nullable!Base64CSV masterGardenPlantFlowerBook;
|
Nullable!Base64CSV masterGardenPlantFlowerBook;
|
||||||
Nullable!Base64CSV masterCharacterFloweringGroups;
|
Nullable!Base64CSV masterCharacterFloweringGroups;
|
||||||
Nullable!Base64CSV masterGardenPlantInsectBook;
|
Nullable!Base64CSV masterGardenPlantInsectBook;
|
||||||
Nullable!Base64CSV masterWhaleEvent;
|
Nullable!Base64CSV masterWhaleEvent;
|
||||||
Nullable!Base64CSV masterCharacterTrainableLeaderSkillLevel;
|
Nullable!Base64CSV masterCharacterTrainableLeaderSkillLevel;
|
||||||
Nullable!Base64CSV masterCharacterPurification;
|
Nullable!Base64CSV masterCharacterPurification;
|
||||||
Nullable!Base64CSV masterDungeon;
|
Nullable!Base64CSV masterDungeon;
|
||||||
Nullable!Base64CSV masterShop;
|
Nullable!Base64CSV masterShop;
|
||||||
Nullable!Base64CSV masterGuest;
|
Nullable!Base64CSV masterGuest;
|
||||||
Nullable!Base64CSV masterAlbumTheater;
|
Nullable!Base64CSV masterAlbumTheater;
|
||||||
Nullable!Base64CSV masterCharacter;
|
Nullable!Base64CSV masterCharacter;
|
||||||
Nullable!Base64CSV masterCharacterEquipmentLevel;
|
Nullable!Base64CSV masterCharacterEquipmentLevel;
|
||||||
Nullable!Base64CSV masterStageConcept;
|
Nullable!Base64CSV masterStageConcept;
|
||||||
Nullable!Base64CSV masterDungeonRecommendTotalPowerGroup;
|
Nullable!Base64CSV masterDungeonRecommendTotalPowerGroup;
|
||||||
Nullable!Base64CSV masterCharacterSkin;
|
Nullable!Base64CSV masterCharacterSkin;
|
||||||
Nullable!Base64CSV masterGardenPlantPot;
|
Nullable!Base64CSV masterGardenPlantPot;
|
||||||
Nullable!Base64CSV masterItemPurification;
|
Nullable!Base64CSV masterItemPurification;
|
||||||
Nullable!Base64CSV masterStageTimeSchedule;
|
Nullable!Base64CSV masterStageTimeSchedule;
|
||||||
Nullable!Base64CSV masterGardenFlowerItem;
|
Nullable!Base64CSV masterGardenFlowerItem;
|
||||||
Nullable!Base64CSV masterPlantItem;
|
Nullable!Base64CSV masterPlantItem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,36 +10,36 @@ import std.typecons : Nullable;
|
||||||
|
|
||||||
class Response
|
class Response
|
||||||
{
|
{
|
||||||
string resultCode;
|
string resultCode;
|
||||||
string buildVersion;
|
string buildVersion;
|
||||||
Nullable!string serverTime;
|
Nullable!string serverTime;
|
||||||
Nullable!string version_;
|
Nullable!string version_;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Base64CSV
|
struct Base64CSV
|
||||||
{
|
{
|
||||||
string[][] records;
|
string[][] records;
|
||||||
|
|
||||||
alias records this;
|
alias records this;
|
||||||
|
|
||||||
@safe //I guess
|
@safe //I guess
|
||||||
string toRepresentation() const
|
string toRepresentation() const
|
||||||
{
|
{
|
||||||
auto csvString = records.map!(r => r.join(",")).array.join("\n").idup ~ "\n";
|
auto csvString = records.map!(r => r.join(",")).array.join("\n").idup ~ "\n";
|
||||||
|
|
||||||
return Base64.encode(cast(const(ubyte[])) csvString);
|
return Base64.encode(cast(const(ubyte[])) csvString);
|
||||||
}
|
}
|
||||||
|
|
||||||
@safe //I guess
|
@safe //I guess
|
||||||
static Base64CSV fromRepresentation(string input)
|
static Base64CSV fromRepresentation(string input)
|
||||||
{
|
{
|
||||||
auto inputString = cast(string) Base64.decode(input).idup;
|
auto inputString = cast(string) Base64.decode(input).idup;
|
||||||
|
|
||||||
auto records = inputString.splitLines.map!(line => line.split(',')).array;
|
auto records = inputString.splitLines.map!(line => line.split(',')).array;
|
||||||
auto base64csv = Base64CSV(records);
|
auto base64csv = Base64CSV(records);
|
||||||
|
|
||||||
assert(base64csv.toRepresentation == input);
|
assert(base64csv.toRepresentation == input);
|
||||||
|
|
||||||
return base64csv;
|
return base64csv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,5 @@ string[uint] characterNames;
|
||||||
|
|
||||||
static this()
|
static this()
|
||||||
{
|
{
|
||||||
mixin(import("characterNames.data.d"));
|
mixin(import("characterNames.data.d"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,5 @@ string[uint] characterBookFlowerLanguage;
|
||||||
|
|
||||||
static this()
|
static this()
|
||||||
{
|
{
|
||||||
mixin(import("characterBookFlowerLanguage.data.d"));
|
mixin(import("characterBookFlowerLanguage.data.d"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,5 @@ string[uint] characterCategories;
|
||||||
|
|
||||||
static this()
|
static this()
|
||||||
{
|
{
|
||||||
mixin(import("characterCategories.data.d"));
|
mixin(import("characterCategories.data.d"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,6 @@ string[uint] characterLeaderSkillDescriptions;
|
||||||
|
|
||||||
static this()
|
static this()
|
||||||
{
|
{
|
||||||
mixin(import("characterLeaderSkillNames.data.d"));
|
mixin(import("characterLeaderSkillNames.data.d"));
|
||||||
mixin(import("characterLeaderSkillDescriptions.data.d"));
|
mixin(import("characterLeaderSkillDescriptions.data.d"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,6 @@ string[uint] skillDescriptions;
|
||||||
|
|
||||||
static this()
|
static this()
|
||||||
{
|
{
|
||||||
mixin(import("skillNames.data.d"));
|
mixin(import("skillNames.data.d"));
|
||||||
mixin(import("skillDescriptions.data.d"));
|
mixin(import("skillDescriptions.data.d"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,5 @@ string[uint] characterTextResource;
|
||||||
|
|
||||||
static this()
|
static this()
|
||||||
{
|
{
|
||||||
mixin(import("characterTextResource.data.d"));
|
mixin(import("characterTextResource.data.d"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,5 @@ string[uint] dungeonNames;
|
||||||
|
|
||||||
static this()
|
static this()
|
||||||
{
|
{
|
||||||
mixin(import("dungeonNames.data.d"));
|
mixin(import("dungeonNames.data.d"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,5 @@ string[uint] guestPartyNames;
|
||||||
|
|
||||||
static this()
|
static this()
|
||||||
{
|
{
|
||||||
mixin(import("guestPartyNames.data.d"));
|
mixin(import("guestPartyNames.data.d"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,5 @@ string[uint] itemNames;
|
||||||
|
|
||||||
static this()
|
static this()
|
||||||
{
|
{
|
||||||
mixin(import("itemNames.data.d"));
|
mixin(import("itemNames.data.d"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ string[uint] missionRewards;
|
||||||
|
|
||||||
static this()
|
static this()
|
||||||
{
|
{
|
||||||
mixin(import("missionNames.data.d"));
|
mixin(import("missionNames.data.d"));
|
||||||
mixin(import("missionDescriptions.data.d"));
|
mixin(import("missionDescriptions.data.d"));
|
||||||
mixin(import("missionRewards.data.d"));
|
mixin(import("missionRewards.data.d"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,5 @@ string[uint] stageNames;
|
||||||
|
|
||||||
static this()
|
static this()
|
||||||
{
|
{
|
||||||
mixin(import("stageNames.data.d"));
|
mixin(import("stageNames.data.d"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ string[uint] worldMapLocationDescriptions;
|
||||||
|
|
||||||
static this()
|
static this()
|
||||||
{
|
{
|
||||||
mixin(import("worldMapLocationNames.data.d"));
|
mixin(import("worldMapLocationNames.data.d"));
|
||||||
mixin(import("worldMapLocationCaptions.data.d"));
|
mixin(import("worldMapLocationCaptions.data.d"));
|
||||||
mixin(import("worldMapLocationDescriptions.data.d"));
|
mixin(import("worldMapLocationDescriptions.data.d"));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue