Compare commits
10 Commits
d4650aac84
...
v0.1.30
| Author | SHA1 | Date | |
|---|---|---|---|
| 697bff9752 | |||
| 0fa2e0540b | |||
| a1a123054f | |||
| 76d581c419 | |||
| 4f91ab9cff | |||
| e6111f8dbd | |||
| 7ec6e385a0 | |||
| 7427357bc5 | |||
| 6b63d54eb8 | |||
| a3df782245 |
+22
-20
@@ -22,36 +22,31 @@ jobs:
|
|||||||
if: ${{ github.event_name == 'push' }}
|
if: ${{ github.event_name == 'push' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
git fetch --tags || true
|
git fetch --tags --force
|
||||||
|
|
||||||
# Determine last tag and log range
|
if LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null); then
|
||||||
if git describe --tags --abbrev=0 >/dev/null 2>&1; then
|
|
||||||
LAST_TAG=$(git describe --tags --abbrev=0)
|
|
||||||
RANGE="${LAST_TAG}..HEAD"
|
RANGE="${LAST_TAG}..HEAD"
|
||||||
else
|
else
|
||||||
LAST_TAG="v0.1.9"
|
LAST_TAG="v0.1.9"
|
||||||
RANGE="HEAD"
|
RANGE="HEAD"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Calculate next version
|
|
||||||
IFS='.' read -r major minor patch <<< "${LAST_TAG#v}"
|
IFS='.' read -r major minor patch <<< "${LAST_TAG#v}"
|
||||||
NEW_VERSION="$major.$minor.$((patch + 1))"
|
NEW_VERSION="$major.$minor.$((patch + 1))"
|
||||||
NEW_TAG="v$NEW_VERSION"
|
|
||||||
|
|
||||||
# Log commits
|
|
||||||
CHANGELOG=$(git log $RANGE --oneline | sed 's/^/* /')
|
CHANGELOG=$(git log $RANGE --oneline | sed 's/^/* /')
|
||||||
[ -z "$CHANGELOG" ] && CHANGELOG="Maintenance build."
|
if [ -z "$CHANGELOG" ]; then
|
||||||
|
CHANGELOG="Re-run of version $NEW_VERSION or maintenance build."
|
||||||
|
fi
|
||||||
|
|
||||||
# Tag and push back to Gitea
|
|
||||||
git tag $NEW_TAG
|
|
||||||
git push origin $NEW_TAG
|
|
||||||
|
|
||||||
# Set outputs for next steps
|
|
||||||
echo "version-string=$NEW_VERSION" >> $GITHUB_OUTPUT
|
echo "version-string=$NEW_VERSION" >> $GITHUB_OUTPUT
|
||||||
echo "changelog<<EOF" >> $GITHUB_OUTPUT
|
echo "new-tag=v$NEW_VERSION" >> $GITHUB_OUTPUT
|
||||||
echo "## What's Changed" >> $GITHUB_OUTPUT
|
{
|
||||||
echo "$CHANGELOG" >> $GITHUB_OUTPUT
|
echo "changelog<<EOF"
|
||||||
echo "EOF" >> $GITHUB_OUTPUT
|
echo "## What's Changed"
|
||||||
|
echo "$CHANGELOG"
|
||||||
|
echo "EOF"
|
||||||
|
} >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Setup Tools Cache
|
- name: Setup Tools Cache
|
||||||
id: tools-cache
|
id: tools-cache
|
||||||
@@ -124,11 +119,18 @@ jobs:
|
|||||||
name: unlocker-build
|
name: unlocker-build
|
||||||
path: unlocker.zip
|
path: unlocker.zip
|
||||||
|
|
||||||
|
- name: Finalize Version and Push Tag
|
||||||
|
if: ${{ github.event_name == 'push' && success() }}
|
||||||
|
run: |
|
||||||
|
git tag ${{ steps.calculate-version.outputs.new-tag }}
|
||||||
|
git push origin ${{ steps.calculate-version.outputs.new-tag }}
|
||||||
|
|
||||||
- name: Create Gitea Release
|
- name: Create Gitea Release
|
||||||
if: ${{ github.event_name == 'push' }}
|
if: ${{ github.event_name == 'push' && success() }}
|
||||||
uses: akkuman/gitea-release-action@v1
|
uses: akkuman/gitea-release-action@v1
|
||||||
with:
|
with:
|
||||||
files: unlocker.zip
|
files: unlocker.zip
|
||||||
tag_name: v${{ steps.calculate-version.outputs.version-string }}
|
tag_name: ${{ steps.calculate-version.outputs.new-tag }}
|
||||||
name: Release v${{ steps.calculate-version.outputs.version-string }}
|
name: Release ${{ steps.calculate-version.outputs.new-tag }}
|
||||||
body: ${{ steps.calculate-version.outputs.changelog }}
|
body: ${{ steps.calculate-version.outputs.changelog }}
|
||||||
|
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
@@ -109,10 +110,11 @@ bool Spoofer::parseCatalog(std::string data)
|
|||||||
auto extractIds = [&](const std::string& key, std::unordered_set<std::string>& targetSet) {
|
auto extractIds = [&](const std::string& key, std::unordered_set<std::string>& targetSet) {
|
||||||
if (catalogData.contains(key) && catalogData[key].contains("items"))
|
if (catalogData.contains(key) && catalogData[key].contains("items"))
|
||||||
for (const auto& id : catalogData[key]["items"])
|
for (const auto& id : catalogData[key]["items"])
|
||||||
if (id.is_string())
|
{
|
||||||
targetSet.insert(id.get<std::string>());
|
if (id.is_string()) targetSet.insert(id.get<std::string>());
|
||||||
else
|
}
|
||||||
Log::warning("Catalog missing or invalid category: {}", key);
|
else
|
||||||
|
Log::warning("Catalog missing or invalid category: {}", key);
|
||||||
};
|
};
|
||||||
|
|
||||||
extractIds("item", _catalogItemIds);
|
extractIds("item", _catalogItemIds);
|
||||||
@@ -142,10 +144,11 @@ bool Spoofer::parseStackable(std::string data, std::unordered_set<std::string>&
|
|||||||
auto populate = [&](const std::string& key, std::unordered_set<std::string>& targetSet) {
|
auto populate = [&](const std::string& key, std::unordered_set<std::string>& targetSet) {
|
||||||
if (doc.contains(key) && doc[key].is_array())
|
if (doc.contains(key) && doc[key].is_array())
|
||||||
for (const auto& item : doc[key])
|
for (const auto& item : doc[key])
|
||||||
if (item.is_string())
|
{
|
||||||
targetSet.insert(item.get<std::string>());
|
if (item.is_string()) targetSet.insert(item.get<std::string>());
|
||||||
else
|
}
|
||||||
Log::warning("Missing stackables array ({})", key);
|
else
|
||||||
|
Log::warning("Missing stackables array ({})", key);
|
||||||
};
|
};
|
||||||
|
|
||||||
populate("Slashers", slasherSet);
|
populate("Slashers", slasherSet);
|
||||||
@@ -271,7 +274,7 @@ void Spoofer::modifyCharacterData(json& js)
|
|||||||
/*
|
/*
|
||||||
ghost node hotfix (untested)
|
ghost node hotfix (untested)
|
||||||
*/
|
*/
|
||||||
/* if (js.contains("bloodWebData") && js["bloodWebData"].contains("ringData"))
|
/* if (js.contains("bloodWebData") && js["bloodWebData"].contains("ringData"))
|
||||||
{
|
{
|
||||||
auto& ringData = js["bloodWebData"]["ringData"];
|
auto& ringData = js["bloodWebData"]["ringData"];
|
||||||
|
|
||||||
@@ -345,12 +348,34 @@ void Spoofer::modifyCharacterData(json& js)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
Log::verbose("Spoofed data for character {}", name);
|
Log::verbose("Spoofed data for character {}", name);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
endpoint handlers
|
endpoint handlers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void Spoofer::onGetCatalogItems(std::string& body)
|
||||||
|
{
|
||||||
|
std::thread t([body]() {
|
||||||
|
std::string outPath = utils::getExePath() + "catalog.json";
|
||||||
|
std::ofstream file(outPath);
|
||||||
|
if (file.is_open())
|
||||||
|
{
|
||||||
|
file << body;
|
||||||
|
file.close();
|
||||||
|
Log::verbose("Raw catalog saved to {}", outPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Log::error("Unable to write to catalog.json");
|
||||||
|
});
|
||||||
|
t.detach();
|
||||||
|
|
||||||
|
parseCatalog(body);
|
||||||
|
}
|
||||||
|
|
||||||
void Spoofer::onGetAll(std::string& body)
|
void Spoofer::onGetAll(std::string& body)
|
||||||
{
|
{
|
||||||
json doc = json::parse(body, nullptr, false);
|
json doc = json::parse(body, nullptr, false);
|
||||||
@@ -424,6 +449,62 @@ void Spoofer::onInventoryAll(std::string& body)
|
|||||||
Log::verbose("Inventory spoofed");
|
Log::verbose("Inventory spoofed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Spoofer::onMessageList(std::string& body)
|
||||||
|
{
|
||||||
|
json doc = json::parse(body, nullptr, false);
|
||||||
|
if (doc.is_discarded()) return Log::error("JSON parse error for dbd-messages/listV2");
|
||||||
|
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
auto now_seconds = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();
|
||||||
|
auto now_milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
|
||||||
|
|
||||||
|
json msg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
msg base
|
||||||
|
*/
|
||||||
|
msg["allowedPlatforms"] = json::array({"egs", "grdk", "ps4", "ps5", "steam", "xbox", "xsx"});
|
||||||
|
msg["flag"] = "READ";
|
||||||
|
msg["gameSpecificData"] = {};
|
||||||
|
msg["read"] = false;
|
||||||
|
msg["tag"] = json::array({"inbox"});
|
||||||
|
msg["expireAt"] = now_seconds + (1337 * 24 * 60 * 60);
|
||||||
|
msg["received"] = now_milliseconds;
|
||||||
|
msg["recipientId"] = "system";
|
||||||
|
|
||||||
|
/*
|
||||||
|
msg content
|
||||||
|
*/
|
||||||
|
json bodyContent;
|
||||||
|
bodyContent["sections"] = json::array();
|
||||||
|
bodyContent["sections"].push_back(
|
||||||
|
{{"type", "text"},
|
||||||
|
{"text", "Japan is turning footsteps into electricity!<br><br>Using piezoelectric tiles, every step "
|
||||||
|
"you take generates a small amount of energy. Millions of steps together can power LED "
|
||||||
|
"lights and displays in busy places like Shibuya Station.<br><br>A brilliant way to create a "
|
||||||
|
"sustainable and smart city — turning movement into clean, renewable energy."}});
|
||||||
|
|
||||||
|
bodyContent["image"] = {
|
||||||
|
{"packagedPath", "/Game/UI/UMGAssets/Icons/ItemAddons/iconAddon_powerBulb.iconAddon_powerBulb"},
|
||||||
|
{"contentVersion", "ccc3f02b0a671fe19a0017d6a69293876a465fd9"},
|
||||||
|
{"uri", ""}};
|
||||||
|
|
||||||
|
bodyContent["sections"].push_back(
|
||||||
|
{{"type", "itemshowcase"},
|
||||||
|
{"rewards", json::array({{{"type", "inventory"}, {"id", "ADDON_flashlight_oddbulb"}, {"amount", 1}}})}});
|
||||||
|
|
||||||
|
msg["message"] = {};
|
||||||
|
msg["message"]["title"] = "Japan is turning footsteps into electricity";
|
||||||
|
msg["message"]["body"] = bodyContent.dump();
|
||||||
|
|
||||||
|
doc["messages"].push_back(msg);
|
||||||
|
|
||||||
|
body = doc.dump();
|
||||||
|
#ifdef _DEBUG
|
||||||
|
Log::verbose("Spoofed message list");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void Spoofer::onBloodweb(std::string& body, std::string& respHeaders)
|
void Spoofer::onBloodweb(std::string& body, std::string& respHeaders)
|
||||||
{
|
{
|
||||||
json doc = json::parse(body, nullptr, false);
|
json doc = json::parse(body, nullptr, false);
|
||||||
@@ -455,13 +536,17 @@ void Spoofer::onBloodweb(std::string& body, std::string& respHeaders)
|
|||||||
respHeaders = std::regex_replace(respHeaders, statusRegex, "HTTP/1.1 200");
|
respHeaders = std::regex_replace(respHeaders, statusRegex, "HTTP/1.1 200");
|
||||||
|
|
||||||
body = mock.dump();
|
body = mock.dump();
|
||||||
|
#ifdef _DEBUG
|
||||||
Log::verbose("Spoofed bloodweb request for unowned character.");
|
Log::verbose("Spoofed bloodweb request for unowned character.");
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
modifyCharacterData(doc);
|
modifyCharacterData(doc);
|
||||||
body = doc.dump();
|
body = doc.dump();
|
||||||
|
#ifdef _DEBUG
|
||||||
Log::verbose("Spoofed bloodweb items for owned character");
|
Log::verbose("Spoofed bloodweb items for owned character");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -476,8 +561,11 @@ void Spoofer::serverResponseHandler(const std::string& url, std::string& body, s
|
|||||||
Log::verbose("BHVR api res @ {}", url);
|
Log::verbose("BHVR api res @ {}", url);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (url.find("api/v1/extensions/store/getCatalogItems") != std::string::npos) return onGetCatalogItems(body);
|
||||||
|
if (url.find("api/v1/dbd-character-data/get-all") != std::string::npos) return onGetAll(body);
|
||||||
if (url.find("api/v1/dbd-character-data/get-all") != std::string::npos) return onGetAll(body);
|
if (url.find("api/v1/dbd-character-data/get-all") != std::string::npos) return onGetAll(body);
|
||||||
if (url.find("api/v1/dbd-inventories/all") != std::string::npos) return onInventoryAll(body);
|
if (url.find("api/v1/dbd-inventories/all") != std::string::npos) return onInventoryAll(body);
|
||||||
|
if (url.find("/api/v1/messages/listV2") != std::string::npos) return onMessageList(body);
|
||||||
if (url.find("api/v1/dbd-character-data/bloodweb") != std::string::npos ||
|
if (url.find("api/v1/dbd-character-data/bloodweb") != std::string::npos ||
|
||||||
url.find("api/v1/dbd-character-data/bulk-spending-bloodweb") != std::string::npos)
|
url.find("api/v1/dbd-character-data/bulk-spending-bloodweb") != std::string::npos)
|
||||||
return onBloodweb(body, respHeaders);
|
return onBloodweb(body, respHeaders);
|
||||||
|
|||||||
@@ -28,8 +28,10 @@ class Spoofer
|
|||||||
void generateBloodweb(nlohmann::json& data);
|
void generateBloodweb(nlohmann::json& data);
|
||||||
void modifyCharacterData(nlohmann::json& js);
|
void modifyCharacterData(nlohmann::json& js);
|
||||||
|
|
||||||
|
void onGetCatalogItems(std::string& body);
|
||||||
void onGetAll(std::string& body);
|
void onGetAll(std::string& body);
|
||||||
void onInventoryAll(std::string& body);
|
void onInventoryAll(std::string& body);
|
||||||
|
void onMessageList(std::string& body);
|
||||||
void onBloodweb(std::string& body, std::string& respHeaders);
|
void onBloodweb(std::string& body, std::string& respHeaders);
|
||||||
|
|
||||||
void serverResponseHandler(const std::string& url, std::string& body, std::string& respHeaders);
|
void serverResponseHandler(const std::string& url, std::string& body, std::string& respHeaders);
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#include <minwindef.h>
|
||||||
|
#include <libloaderapi.h>
|
||||||
|
|
||||||
|
std::string utils::getExePath()
|
||||||
|
{
|
||||||
|
char buffer[MAX_PATH];
|
||||||
|
GetModuleFileNameA(NULL, buffer, MAX_PATH);
|
||||||
|
std::string path(buffer);
|
||||||
|
size_t pos = path.find_last_of("\\/");
|
||||||
|
if (pos != std::string::npos) return path.substr(0, pos + 1);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
std::string getExePath();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user