BMAG v2.0.0: Rewrite#8
Conversation
Taking a break for a bit. There will be a part 2 for this commit. Mostly consists of restructuring the program as well as changing variable names to be more accurate. Might revert some in pt.2
Slowly but surely this codebase will make sense to me
Refactor codebase
Remove Handy mention
`sed` messed up one of the localization strings
Create issue templates for GitHub tracking
Update issue templates
Merge pull request #7 from uptudev/main
Added headers to make reading issues easier
Update issue templates
- Notes on v2 development can be found in the GitHub Issues. - Legacy code removed.
modify: * `./LICENSE`: replace GPLv3 license with modified MIT/X11 license. delete: - `./README_JP.md`: remove old docs not written by me - `./README_ZH.md`: remove old docs not written by me - `./config.lua`: remove old GPLv3 licensed code - `./localization/en-us.lua`: remove old GPLv3 licensed code - `./localization/ja.lua`: remove old GPLv3 licensed code - `./localization/zh_CN.lua`: remove old GPLv3 licensed code Signed-off-by: uptu <uptu@uptu.dev>
create: + `./src/main.lua`: add main source code file modify: * `./bmag.lua`: change to only contain Steamodded metadata and a `load_file` call to `./src/main.lua` Signed-off-by: uptu <uptu@uptu.dev>
create: + `./CHANGELOG.md`: add a CHANGELOG compliant with the standards set out at https://keepachangelog.com/ Signed-off-by: uptu <uptu@uptu.dev>
create: + `./src/libs/timers.lua`: add an implementation for a table for tracking monotonic keypress timers modify: * `./queue.lua` -> `./src/libs/queue.lua`: move the queue implementation to the `libs` directory Signed-off-by: uptu <uptu@uptu.dev>
create: + `./.dev/hooks/commit-msg`: add hook to sign off on git commit messages + `./.dev/hooks/post-checkout`: add hook to run a bootstrapping script on checkout
create: + `./.dev/commit-template`: add a default git commit template
modify: * `./.dev/hooks/commit-msg`: sign the commit message in-place
create: + `./.dev/bootstrap.sh`: add bootstrapping script Signed-off-by: uptu <uptu@uptu.dev>
modify: * `./.dev/bootstrap.sh`: Error catching and pipeline fix Signed-off-by: uptu <uptu@uptu.dev>
create: + `./CONTRIBUTING.md`: add contribution guidelines Signed-off-by: uptu <uptu@uptu.dev>
modify: * `./.dev/bootstrap.sh`: should be all fixed now ;-; Signed-off-by: uptu <uptu@uptu.dev>
create: + `./CODE_OF_CONDUCT.md`: add the Code of Conduct to the repo, based off of Contributor Covenant v2.1 Signed-off-by: uptu <uptu@uptu.dev>
modify: * `./CHANGELOG.md`: reformat to include some missing features * `./README.md`: add a video preview of the mod at work Signed-off-by: uptu <uptu@uptu.dev>
modify: * `./README.md`: replace video link with GitHub built-in embedded video
|
Thank you. I’ll consider merging or transferring this at a later time. That said, I still believe some of BMag’s unique features could be integrated into Handy without too much difficulty—this might be simpler than a full rewrite. I’d suggest reevaluating both approaches. |
|
Apologies for the long delay in addressing this project. I tested version 2.0.1 and noticed that a long right-click incorrectly triggers buttons outside the hand zone (e.g., "Sort Hand," "Play Hand," "View Deck," "Options," etc.). My original implementation included area restrictions to prevent this. Additionally, I see you replaced the default Sort and Play/Discard key bindings. While the current version makes customization convenient, I’d like to note that most users are likely accustomed to the original key layout. Moreover, since Play/Discard is used more frequently than Sort, and many mice lack side buttons, assigning the scroll wheel to Play/Discard by default might be more practical. |
modify: * `./src/libs/feat.lua`: add two missing `if` statements to ensure that the multiselect target is a `Card` and not a UI element like the Sort, Discard, or Play buttons. Signed-off-by: uptu <uptu@uptu.dev>
modify: * `./CHANGELOG.md`: add v2.0.2 changes * `./bmag.json`: increment mod version to `2.0.2` Signed-off-by: uptu <uptu@uptu.dev>
|
Patched that error with an Regarding the control switch, it's extremely easy to accidentally play or discard a hand by bumping the scroll wheel. The change was due to the fact that accidentally sorting your hand is much less detrimental to a run than accidentally playing or discarding a hand because you grabbed your mouse too quickly or bumped the wheel with your fingers. Given the controls can be rebound much easier, I thought that having a default that is safe and less error prone may be best. If you want, I can change it later tonight, as it just involves swapping out the default table entries in |
|
You're absolutely right. I had considered the potential for accidental triggers before but didn't address it thoroughly. Let’s proceed with your suggested default setup. I’ll continue with some additional testing and add localization support. If everything goes well, I plan to merge this pull request soon. |
|
A few additional minor issues:
|
modify: * `./src/libs/feats.lua`: fix a crash when holding the `multiselect` bind down and clicking on a menu button Signed-off-by: uptu <uptu@uptu.dev>
modify: * `./src/libs/feats.lua`: remove the ability to select non-hand cards with multiselect Signed-off-by: uptu <uptu@uptu.dev>
modify: * `./src/libs/feats.lua`: refactor multiselect to ensure multiselecting only happens after the user has moved the mouse * `./src/libs/timers.lua`: set/unset multiselect start position on keypress * `./src/main.lua`: add multiselect start position to mod state Signed-off-by: uptu <uptu@uptu.dev>
Fixed by
Both fixed by
Fixed by Drafting a new release right now on my repo; let me know if you find any other issues :) |
modify: * `./CHANGELOG.md`: update with `v2.0.3` changes * `./bmag.json`: increment version number Signed-off-by: uptu <uptu@uptu.dev>
modify: * `./src/libs/feats.lua`: fix a minor error introduced during multiselect refactor where some state variables wouldn't be populated correctly (unlikely but a possible bug regardless) * `./src/main.lua`: add `prev_target` to mod state variables to use instead of `G.CONTROLLER.hovering.prev_target`, which the engine overwrites during gameplay, causing erroneous behaviour where one could spam-click a card by putting the cursor over the blank space a card moves into/away from when selected Signed-off-by: uptu <uptu@uptu.dev>
|
Fixed a minor error caused by using game state variables, which allowed the user to spam a card if they got their cursor in the right spot. It's unlikely to cause issues in gameplay, but I fixed it anyways. There was also one more issue that I found where I assign the (ignore the force-push; I forgot to update the changelog correctly, then forgot to add it to the commit lol) |
modify: * `./CHANGELOG.md`: add `v2.0.4` changes * `./bmag.json`: increment version number to `v2.0.4` Signed-off-by: uptu <uptu@uptu.dev>
|
Thank you for your efforts, all the previous issues have been resolved. However, I've noticed a few problems with the keybinds:
Additional suggestions:
|
|
I don't know if you have another mod interfering with your input on your end, but multiselect can be bound perfectly fine as of v2.0.4 on my end beyond a minor visual glitch when attempting to rebind the first time; subsequent attempts to rebind work fine. I also cannot replicate your issue with being unable to trigger the restart feature, as it can be bound to either clicks or holds (unbound by default though, because it's the most potentially destructive bind), and both of them work on my end as well. I even removed my old configuration and tried from a new install and it worked fine. Please let me know if the v2.0.5 changes fixed the issue, as they solved the visual glitches I found. Also ensure you are holding the key down as indicated when trying to rebind any 'hold-only' binds; 'click'-style features like hand sorting and play/discard can be bound to either keypresses or keyholds, but multiselect must be bound to some keyhold, not a press. I'll be releasing another minor patch in a few minutes with fixes for the visual glitches in the config menu, but as mentioned earlier I couldn't replicate your issues with multiselect nor with the restart function, so I can't patch it unless you can provide more info such as a crash dump or recording of the erroneous behaviour. Regarding the suggestions:
StickyKeys is OS-specific behaviour that can be disabled from within Windows, and should be unless you explicitly require it; there's no need to further limit input options beyond disallowing
That is a byproduct of how the Love2D game engine operates; any part of the input handling of the game works through frame updates, and input hooks like this mod are bottlenecked by it. In theory a line could be inscribed from the beginning of your multiselect to the end, and any cards that contact that line could be highlighted, but this would be neither more responsive nor easier to implement (if even possible with the way the game operates). You cannot process input any faster than the computer is already processing the rest of the game without creating a forked process that hooks into the memory of the game, but that would involve creating a project similar to DFHack for Balatro; as such, there's no feasible way to really fix it. |
modify: * `./src/libs/input.lua`: fix inconsistent coding style Signed-off-by: uptu <uptu@uptu.dev>
modify: * `./localization/en-us.lua`: add localization key for reset button text; removed brackets from button text * `./src/libs/config.lua`: add reset button to config menu; fix buggy config functions Signed-off-by: uptu <uptu@uptu.dev>
modify: * `./CHANGELOG.md`: add `v2.0.5` changes * `./bmag.json`: increment version number to `v2.0.5` Signed-off-by: uptu <uptu@uptu.dev>
Let me know if these are still issues for you with |
|
I hadn't realized there was a distinction between clicking and long-pressing in the config interface, as most games allow keybinds to be set with a simple click—regardless of whether the actual in-game action is a click or a hold. Although I noticed the hint text at the top, I didn’t read it carefully and simply followed my intuition when setting the keys. Even though you’ve added a clearer prompt in version 2.0.5, I’m still not entirely sure whether all players will notice this detail. Because of this, I initially tried to set the multiselect key with a click (rather than a long press), and then attempted to use the reset function (which I’d set with a click) by holding the key down. After understanding the intended behavior, I was able to configure and use the keys correctly. However, I’m still uncertain whether distinguishing between click and long-press during keybinding aligns with most players’ intuition. Regarding the restriction of bindable keys—aside from the Windows key, which can cause more noticeable issues—other keys don’t really have significant drawbacks. It’s reasonable to let players decide their own key mappings, so the current approach is fine. As for the rapid movement issue during multiselect, one possible solution is to sample the mouse position at short intervals (e.g., every 10 frames, though this would need testing) and check for collisions with card hitboxes along the path formed by these points. It’s important not to only record the start and end positions, since players sometimes need to select cards in a non-linear pattern (e.g., drawing a wavy line with the mouse). You can explore whether this is feasible to implement, though I agree it may be a relatively low-priority fix. Other bugs:
Enhancement: |
|
No. Quit responding to me using AI prompts. I've been doing software engineering for over a decade and a half, and I don't need someone getting a chatbot to reiterate what I already said, then providing suggestions they cannot even be bothered to verify, especially when they regularly hallucinate bugs that don't exist. It's a massive waste of my time as someone trying to contribute this PR for over 2 months. Has your LLM considered the computational cost of checking a bounding box every few frames may be massive when we've already determined pegging input processing to a potentially slow framerate is the bottleneck in the hypothetical you're trying to solve? Parsing input a tenth of the time using collision functions 10x as computationally intensive that probably don't even exist in the engine won't fix anything; Love2D almost certainly doesn't have a way to iterate over every entity making contact with a line, as that would require iterating over every single game object every frame input is parsed. As mentioned earlier when I went over the pros and cons, it's neither feasible to implement, nor more responsive, as cards would only be highlighted every 10 frames. Listen to what I'm saying and stop asking an LLM trained on millions of unoptimized web dev portfolios to give you suggestions. I'm not adding more extraneous shit; there are over 90 commits in this pull request. Accept the PR or don't. Regarding the "bugs", the 'Save' button saves your configuration to disk for any subsequent game launches. It's not an 'Apply' button; any bindings set in the menu are immediately applied, and that is intended behaviour when changing settings in a menu. I might fix the second bug if it actually exists this time. I have doubts given lines 125-129 and 151-155 in
Not when you can bind both clicks and holds to all but one feature; it's called consistency. How many games has the AI that wrote this played again? Oh yeah, zero, so maybe stop asking it. |
|
I apologize for the various delays, careless issue submissions, and unwise suggestions I've caused since you submitted this PR. I am an amateur developer with only basic computer and programming knowledge, so I did rely heavily on free AI Q&A tools during my mod development process. However, in this PR, all my questions and suggestions were based on my own testing and ideas—at this point I wasn’t being careless. The only part where I used AI was for English translation, as I’m not a native speaker and my English skills are limited. Of course, given my limited knowledge, some of my replies might not even be as good as those from free AI, so I'm sorry about this. I didn't respond for over a month during this period. My life circumstances weren't great at the time, so I didn't feel like putting effort into this, even though I actually had quite a bit of free time. I truly neglected the results of your hard work, I did it wrong. Although I only performed simple testing and provided feedback during this PR process, I still learned a lot about GitHub and PRs. Since you are the first person I’ve submitted a PR to on GitHub, I truly appreciate your generosity and enthusiastic guidance. My mod has many imperfect aspects, the code is poorly written, and it's already considered outdated on Discord. I believe your substantial improvements can breathe new life into it. Regarding the rapid movement issue, I admit my consideration was superficial, and I didn’t actually attempt to solve it. As you pointed out, it seems like more trouble than it’s worth. Fortunately, this issue has little practical impact and can be ignored. About the save function: In my experience, most games with an "Apply" button in the keybinding settings require clicking it to save the settings for the current and future sessions. If players don’t click "Apply" and exit directly, the changes aren’t saved. Players might not realize that settings are saved in real time and "Apply" is meant for subsequent game launches. On the other hand, if there’s no "Apply" button, it’s natural to assume settings are saved in real time. Your current approach combines these two common methods, which feels counterintuitive and requires additional adaptation. If this is a limitation of Love2D or smods, perhaps more eye-catching explanatory text should be added. Regarding the second bug, I can consistently reproduce it (game version, smods, and lovely are all up-to-date, with only bmag installed):
If needed, I can provide a video with keypress visualization. About binding keys with clicks and holds: In all the games I’ve played, I’ve never encountered a scenario where holding a key was required for binding. This feels very counterintuitive I think. I also checked several games in my Steam library (like Slay the Spire, Celeste, Monster Hunter or Apex, etc.) and found no such cases. Keybinding typically involves either clicking to input, selecting from options, or assigning a function to a key. Specifically, in games where clicking and holding perform different actions, the conditions and effects are either:
Thus, even if one key corresponds to multiple functions, only a single key needs to be bound. The distinction between click and hold is handled internally by the game, and users only need to click during keybinding. Our mod may belongs to the second category. Combining this with the ability to bind both clicks and holds (which is counterintuitive) further blurs the line between binding input and actual operation. I think it would be better to restrict multiselect and restart to hold-only actions, while other functions are click-only. This would limit all keybinding inputs to clicks. Given the mod’s limited functions, there’s no need to conserve key slots by using holds. This approach wouldn’t restrict user freedom too much, would be more intuitive, and would avoid unexpected issues. I'm not sure if I'm overthinking the issue of distinguishing between clicks and holds during keybinding. Although it's easy to adapt once you understand the logic, I did experience significant confusion during my initial use. I hope my suggestions provide some useful insights. If you’re busy, there’s no need to reply quickly—feel free to respond and optimize at your own pace. |
Completely rewrote the mod from scratch, adding a binding menu which allows binding any key or button to any function.
Default settings are still the same, but you can now rebind any of the mod functions.All old GPLv3-licensed code was replaced with new MIT/X11-licensed code, as GPLv3 prohibits shipping software with proprietary code, which Balatro might contain. Steamodded metadata has been updated to the new v1.0.0 format, and a
CHANGELOG.md,CODE_OF_CONDUCT.mdandCONTRIBUTING.mdhave been added to track changes and outline contribution guidelines.Files in
./.devare used to bootstrap the development process, and shouldn't be included in release archives. The only files that should be included in the releases are:./localization/,./src/,./bmag.json,./LICENSE, and./README.md.To preview, I have v2.0.0 as a release on my fork of the repo here. I will be testing it out in the meantime to ensure no bugs slipped through, but all code is documented and straightforward.