Skip to content
This repository was archived by the owner on Aug 2, 2026. It is now read-only.

Commit 422beb9

Browse files
committed
Fixes and Additions
1 parent e613089 commit 422beb9

6 files changed

Lines changed: 132 additions & 83 deletions

File tree

changelog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# 2.1.4
2+
- Add custom spritesheet support (Experimental)
3+
- Add `cascade-color` and `cascade-opacity` bools
4+
- Attempt to fix random sprites not working
5+
- Fix getting by index not working with query selectors
6+
17
# 2.1.3
28
- Fix bug where getting by index required the full namespace of the type
39

mod.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
{
2-
"geode": "5.0.0",
2+
"geode": "5.3.0",
33
"gd": {
44
"win": "2.2081",
55
"android": "2.2081",
66
"mac": "2.2081",
77
"ios": "2.2081"
88
},
9-
"version": "v2.1.3",
9+
"version": "v2.1.4",
1010
"id": "alphalaneous.happy_textures",
1111
"name": "Happy Textures :3",
1212
"developer": "Alphalaneous",
1313
"description": "Texture Packs on a whole new level!",
1414
"early-load": true,
1515
"dependencies": {
1616
"geode.node-ids": ">=v1.15.0",
17-
"alphalaneous.alphas_geode_utils": ">=v1.2.0-beta.2",
17+
"alphalaneous.alphas_geode_utils": ">=v1.2.3",
1818
"prevter.imageplus": {
1919
"required": true,
2020
"version": ">=v1.0.0"

src/UIModding.cpp

Lines changed: 75 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -731,8 +731,7 @@ std::vector<std::string> UIModding::generateValidSprites(const std::string& path
731731
void UIModding::setSprite(CCNode* node, const matjson::Value& attributes) {
732732
if (!attributes.contains("sprite") && !attributes.contains("sprite-frame")) return;
733733

734-
matjson::Value sprite = attributes["sprite"];
735-
if (attributes.contains("sprite-frame")) sprite = attributes["sprite-frame"];
734+
matjson::Value sprite = attributes.contains("sprite-frame") ? attributes["sprite-frame"] : attributes["sprite"];
736735
std::string spriteName;
737736
CCSprite* spr = nullptr;
738737

@@ -820,6 +819,40 @@ void UIModding::setSprite(CCNode* node, const matjson::Value& attributes) {
820819
}
821820
}
822821

822+
void UIModding::setCascadeColor(CCNode* node, const matjson::Value& attributes) {
823+
if (!attributes.contains("cascade-color")) return;
824+
825+
if (auto cascade = attributes["cascade-color"]; cascade.isBool()) {
826+
if (auto node1 = typeinfo_cast<CCMenuItemSpriteExtra*>(node)) {
827+
node1->setCascadeColorEnabled(cascade.asBool().unwrap());
828+
if (auto node2 = node1->getChildByType<ButtonSprite>(0)) {
829+
node2->setCascadeColorEnabled(cascade.asBool().unwrap());
830+
}
831+
}
832+
833+
if (auto rgba = typeinfo_cast<CCRGBAProtocol*>(node)) {
834+
rgba->setCascadeColorEnabled(cascade.asBool().unwrap());
835+
}
836+
}
837+
}
838+
839+
void UIModding::setCascadeOpacity(CCNode* node, const matjson::Value& attributes) {
840+
if (!attributes.contains("cascade-opacity")) return;
841+
842+
if (auto cascade = attributes["cascade-opacity"]; cascade.isBool()) {
843+
if (auto node1 = typeinfo_cast<CCMenuItemSpriteExtra*>(node)) {
844+
node1->setCascadeOpacityEnabled(cascade.asBool().unwrap());
845+
if (auto node2 = node1->getChildByType<ButtonSprite>(0)) {
846+
node2->setCascadeOpacityEnabled(cascade.asBool().unwrap());
847+
}
848+
}
849+
850+
if (auto rgba = typeinfo_cast<CCRGBAProtocol*>(node)) {
851+
rgba->setCascadeOpacityEnabled(cascade.asBool().unwrap());
852+
}
853+
}
854+
}
855+
823856
void UIModding::setOpacity(CCNode* node, const matjson::Value& attributes) {
824857
if (!attributes.contains("opacity")) return;
825858

@@ -835,11 +868,8 @@ void UIModding::setOpacity(CCNode* node, const matjson::Value& attributes) {
835868
}
836869
}
837870

838-
if (auto nodeRGBA = typeinfo_cast<CCNodeRGBA*>(node)) {
839-
nodeRGBA->setOpacity(opacityNum);
840-
}
841-
if (auto layerRGBA = typeinfo_cast<CCLayerRGBA*>(node)) {
842-
layerRGBA->setOpacity(opacityNum);
871+
if (auto rgba = typeinfo_cast<CCRGBAProtocol*>(node)) {
872+
rgba->setOpacity(opacityNum);
843873
}
844874
}
845875

@@ -908,72 +938,53 @@ void UIModding::setScale(CCNode* node, const matjson::Value& attributes) {
908938
}
909939

910940
if (auto fit = scale["fit"]; fit.isObject()) {
911-
std::string fitRelative = fit["relative"].asString().unwrapOrDefault();
912-
float scaleMultiplier = fit["multiplier"].asDouble().unwrapOr(1.f);
913-
CCSize targetSize = {-1, -1};
914-
CCSize screenSize = CCDirector::get()->getWinSize();
915-
CCSize parentSize = targetSize;
916-
if (auto parent = node->getParent()) {
917-
parentSize = parent->getContentSize();
918-
}
919-
if (fitRelative == "screen") {
920-
targetSize = screenSize;
921-
}
922-
if (fitRelative == "screen-width") {
923-
targetSize.width = screenSize.width;
924-
}
925-
if (fitRelative == "screen-height") {
926-
targetSize.height = screenSize.height;
927-
}
928-
if (fitRelative == "parent") {
929-
targetSize = parentSize;
930-
}
931-
if (fitRelative == "parent-width") {
932-
targetSize.width = parentSize.width;
933-
}
934-
if (fitRelative == "parent-height") {
935-
targetSize.height = parentSize.height;
936-
}
937-
if (fitRelative == "size") {
938-
if (auto size = fit["size"]; fit.isObject()) {
939-
if (auto widthVal = size["width"]; widthVal.isNumber()) {
940-
targetSize.width = widthVal.asDouble().unwrapOr(-1.f);
941+
std::string relative = fit["relative"].asString().unwrapOr("screen");
942+
std::string mode = fit["mode"].asString().unwrapOr("fit");
943+
float multiplier = fit["multiplier"].asDouble().unwrapOr(1.f);
944+
945+
CCSize screen = CCDirector::get()->getWinSize();
946+
CCSize parent = node->getParent() ? node->getParent()->getContentSize() : CCSize{0,0};
947+
CCSize target = {-1, -1};
948+
949+
if (relative == "screen") target = screen;
950+
else if (relative == "screen-width") target.width = screen.width;
951+
else if (relative == "screen-height") target.height = screen.height;
952+
else if (relative == "parent") target = parent;
953+
else if (relative == "parent-width") target.width = parent.width;
954+
else if (relative == "parent-height") target.height = parent.height;
955+
else if (relative == "size") {
956+
if (auto size = fit["size"]; size.isObject()) {
957+
if (size["width"].isNumber()) {
958+
target.width = size["width"].asDouble().unwrapOr(-1.f);
941959
}
942-
if (auto heightVal = size["height"]; heightVal.isNumber()) {
943-
targetSize.height = heightVal.asDouble().unwrapOr(-1.f);
960+
if (size["height"].isNumber()) {
961+
target.height = size["height"].asDouble().unwrapOr(-1.f);
944962
}
945963
}
946964
}
947965

948-
CCSize contentSize = node->getContentSize();
966+
CCSize content = node->getContentSize();
949967

950-
float largestSide = -1;
951-
float largestContentSide = -1;
968+
float scaleX = target.width > 0 ? target.width / content.width : -1.f;
969+
float scaleY = target.height > 0 ? target.height / content.height : -1.f;
952970

953-
if (targetSize.width != -1 && targetSize.height != -1) {
954-
if (targetSize.width > targetSize.height) {
955-
largestSide = targetSize.width;
956-
largestContentSide = contentSize.width;
957-
}
958-
else {
959-
largestSide = targetSize.height;
960-
largestContentSide = contentSize.height;
961-
}
971+
if (mode == "stretch") {
972+
if (scaleX > 0) node->setScaleX(scaleX * multiplier);
973+
if (scaleY > 0) node->setScaleY(scaleY * multiplier);
974+
return;
962975
}
963-
else if (targetSize.width != -1 ) {
964-
largestSide = targetSize.width;
965-
largestContentSide = contentSize.width;
976+
977+
float finalScale = -1.f;
978+
979+
if (scaleX > 0 && scaleY > 0) {
980+
finalScale = (mode == "fill") ? std::max(scaleX, scaleY) : std::min(scaleX, scaleY);
966981
}
967-
else if (targetSize.height != -1 ) {
968-
largestSide = targetSize.height;
969-
largestContentSide = contentSize.height;
982+
else {
983+
finalScale = std::max(scaleX, scaleY);
970984
}
971-
972-
if (largestSide != -1) {
973-
float scale = largestSide / largestContentSide;
974-
node->setScale(scale * scaleMultiplier);
985+
if (finalScale > 0) {
986+
node->setScale(finalScale * multiplier);
975987
}
976-
return;
977988
}
978989
}
979990

@@ -1080,6 +1091,8 @@ void UIModding::handleAttributes(CCNode* node, const matjson::Value& attributes)
10801091
nodesFor(setContentSize);
10811092
nodesFor(setVisible);
10821093
nodesFor(setIgnoreAnchorPos);
1094+
nodesFor(setCascadeColor);
1095+
nodesFor(setCascadeOpacity);
10831096
nodesFor(setColor);
10841097
nodesFor(setOpacity);
10851098
nodesFor(setPosition);

src/UIModding.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ class UIModding {
5959
void setFlip(CCNode* node, const matjson::Value& attributes);
6060
void setBlending(CCNode* node, const matjson::Value& attributes);
6161
void setSprite(CCNode* node, const matjson::Value& attributes);
62+
void setCascadeColor(CCNode* node, const matjson::Value& attributes);
63+
void setCascadeOpacity(CCNode* node, const matjson::Value& attributes);
6264
void setOpacity(CCNode* node, const matjson::Value& attributes);
6365
void setShow(CCNode* node, const matjson::Value& attributes);
6466
void setDisablePages(CCNode* node, const matjson::Value& attributes);

src/Utils.hpp

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
#pragma once
22

33
#include <Geode/Geode.hpp>
4-
#include "Geode/cocos/cocoa/CCObject.h"
5-
#include "Geode/utils/cocos.hpp"
6-
#include "Geode/utils/random.hpp"
7-
#include "Geode/utils/string.hpp"
84
#include "UIModding.hpp"
95
#include "Macros.hpp"
106
#include <geode.texture-loader/include/TextureLoader.hpp>
@@ -15,6 +11,17 @@ using namespace geode::prelude;
1511

1612
namespace Utils {
1713

14+
static std::string_view extract(std::string_view s) {
15+
if (auto pos = s.rfind("::"); pos != std::string_view::npos)
16+
return s.substr(pos + 2);
17+
return s;
18+
}
19+
20+
static std::string_view getObjectName(CCObject* obj) {
21+
auto name = cocos::getObjectName(obj);
22+
return extract(std::string(name));
23+
}
24+
1825
class BFSNodeTreeCrawler final {
1926
private:
2027
std::queue<CCNode*> m_queue;
@@ -160,15 +167,15 @@ namespace Utils {
160167
}
161168

162169
if (!m_targetClass.empty()) {
163-
if (getObjectName(node) != m_targetClass) {
170+
if (Utils::getObjectName(node) != m_targetClass) {
164171
return nullptr;
165172
}
166173

167174
if (auto parent = node->getParent()) {
168175
int matchCount = 0;
169176
bool found = false;
170177
for (auto c : CCArrayExt<CCNode*>(parent->getChildren())) {
171-
if (getObjectName(node) == m_targetClass) {
178+
if (Utils::getObjectName(node) == m_targetClass) {
172179
if (matchCount == m_targetIndex) {
173180
if (c != node) return nullptr;
174181
found = true;
@@ -225,17 +232,6 @@ namespace Utils {
225232
}
226233
};
227234

228-
static std::string_view extract(std::string_view s) {
229-
if (auto pos = s.rfind("::"); pos != std::string_view::npos)
230-
return s.substr(pos + 2);
231-
return s;
232-
}
233-
234-
static std::string_view getObjectName(CCObject* obj) {
235-
auto name = cocos::getObjectName(obj);
236-
return extract(std::string(name));
237-
}
238-
239235
static std::optional<cocos2d::CCNode*> getChildByClassName(cocos2d::CCNode* node, geode::ZStringView name, int index = 0) {
240236
if (!node || node->getChildrenCount() == 0) return nullptr;
241237

@@ -252,7 +248,7 @@ namespace Utils {
252248
isNegativeIndex ? --i : ++i) {
253249

254250
auto idxNode = node->getChildrenExt()[i];
255-
if (getObjectName(idxNode) == name) {
251+
if (Utils::getObjectName(idxNode) == name) {
256252
if (indexCounter == index) {
257253
return idxNode;
258254
}
@@ -416,6 +412,37 @@ namespace Utils {
416412
}
417413
}
418414

415+
static void loadCustomSpriteSheets() {
416+
auto& filenameCache = UIModding::get()->filenameCache;
417+
418+
for (const auto& pack : Utils::getActivePacks()) {
419+
auto path = pack.resourcesPath;
420+
if (!std::filesystem::is_directory(path)) continue;
421+
422+
auto spritesheetsDir = path / "spritesheets";
423+
424+
const auto packStr = utils::string::pathToString(path);
425+
const size_t baseLen = packStr.length() + 1;
426+
427+
for (auto& entry : std::filesystem::recursive_directory_iterator(spritesheetsDir)) {
428+
if (!entry.is_regular_file()) continue;
429+
430+
auto extension = utils::string::pathToString(entry.path().extension());
431+
utils::string::toLowerIP(extension);
432+
433+
if (extension != ".plist") continue;
434+
435+
auto full = utils::string::pathToString(entry.path());
436+
437+
qualityToNormal(full);
438+
439+
if (CCSpriteFrameCache::get()->m_pLoadedFileNames->contains(full)) continue;
440+
441+
CCSpriteFrameCache::get()->addSpriteFramesWithFile(full.c_str());
442+
}
443+
}
444+
}
445+
419446
static bool spriteExistsInPacks(const std::string& fileName) {
420447
return UIModding::get()->filenameCache[fileName];
421448
}

src/nodes/LoadingLayer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class $modify(MyLoadingLayer, LoadingLayer) {
1616
UIModding::get()->firstMenuLayer = true;
1717
Utils::clearCaches();
1818
Utils::reloadFileNames();
19+
Utils::loadCustomSpriteSheets();
1920
UIModding::get()->loadNodeFiles();
2021
Config::get()->loadPackJsons();
2122
return LoadingLayer::init(p1);

0 commit comments

Comments
 (0)