Skip to content

Commit b96e623

Browse files
committed
feat: add render on api env var / flag
1 parent 7b77fae commit b96e623

File tree

4 files changed

+86
-12
lines changed

4 files changed

+86
-12
lines changed

balatro.sh

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ declare -a FAILED_PORTS=()
77
HEADLESS=false
88
FAST=false
99
AUDIO=false
10+
RENDER_ON_API=false
1011
FORCE_KILL=true
1112
KILL_ONLY=false
1213
STATUS_ONLY=false
@@ -35,21 +36,24 @@ Usage: $0 [OPTIONS]
3536
$0 --status
3637
3738
Options:
38-
-p, --port PORT Specify port for Balatro instance (can be used multiple times)
39-
Default: 12346 if no port specified
40-
--headless Enable headless mode (sets BALATROBOT_HEADLESS=1)
41-
--fast Enable fast mode (sets BALATROBOT_FAST=1)
42-
--audio Enable audio (disabled by default, sets BALATROBOT_AUDIO=1)
43-
--kill Kill all running Balatro instances and exit
44-
--status Show information about running Balatro instances
45-
-h, --help Show this help message
39+
-p, --port PORT Specify port for Balatro instance (can be used multiple times)
40+
Default: 12346 if no port specified
41+
--headless Enable headless mode (sets BALATROBOT_HEADLESS=1)
42+
--fast Enable fast mode (sets BALATROBOT_FAST=1)
43+
--audio Enable audio (disabled by default, sets BALATROBOT_AUDIO=1)
44+
--render-on-api Enable on-demand rendering - draws frame only on API calls
45+
Incompatible with --headless
46+
--kill Kill all running Balatro instances and exit
47+
--status Show information about running Balatro instances
48+
-h, --help Show this help message
4649
4750
Examples:
4851
$0 # Start single instance on default port 12346
4952
$0 -p 12347 # Start single instance on port 12347
5053
$0 -p 12346 -p 12347 # Start two instances on ports 12346 and 12347
5154
$0 --headless --fast # Start with headless and fast mode on default port
5255
$0 --audio # Start with audio enabled on default port
56+
$0 --render-on-api # Start with on-demand rendering on default port
5357
$0 --kill # Kill all running Balatro instances
5458
$0 --status # Show running instances
5559
@@ -84,6 +88,10 @@ parse_arguments() {
8488
AUDIO=true
8589
shift
8690
;;
91+
--render-on-api)
92+
RENDER_ON_API=true
93+
shift
94+
;;
8795
--kill)
8896
KILL_ONLY=true
8997
shift
@@ -134,6 +142,15 @@ parse_arguments() {
134142
fi
135143
done
136144
PORTS=("${unique_ports[@]}")
145+
146+
# Validate mutually exclusive options
147+
if [[ "$RENDER_ON_API" == "true" ]] && [[ "$HEADLESS" == "true" ]]; then
148+
echo "Error: --render-on-api and --headless are mutually exclusive" >&2
149+
echo "Choose one rendering mode:" >&2
150+
echo " --headless No rendering at all (most efficient)" >&2
151+
echo " --render-on-api Render only on API calls" >&2
152+
exit 1
153+
fi
137154
}
138155

139156
# Check if a port is available
@@ -252,6 +269,9 @@ start_balatro_instance() {
252269
if [[ "$AUDIO" == "true" ]]; then
253270
export BALATROBOT_AUDIO=1
254271
fi
272+
if [[ "$RENDER_ON_API" == "true" ]]; then
273+
export BALATROBOT_RENDER_ON_API=1
274+
fi
255275

256276
# Set up platform-specific Balatro configuration
257277
# Platform-specific launch

balatrobot.lua

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ assert(SMODS.load_file("src/lua/api.lua"))()
44
assert(SMODS.load_file("src/lua/log.lua"))()
55
assert(SMODS.load_file("src/lua/settings.lua"))()
66

7-
-- Initialize API
7+
-- Apply all configuration and Love2D patches FIRST
8+
-- This must run before API.init() to set G.BALATROBOT_PORT
9+
SETTINGS.setup()
10+
11+
-- Initialize API (depends on G.BALATROBOT_PORT being set)
812
API.init()
913

1014
-- Initialize Logger
1115
LOG.init()
1216

13-
-- Apply all configuration and Love2D patches
14-
SETTINGS.setup()
15-
1617
sendInfoMessage("BalatroBot loaded - version " .. SMODS.current_mod.version, "BALATROBOT")

src/lua/api.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ function API.update(_)
150150
)
151151
else
152152
sendDebugMessage(data.name .. "(" .. json.encode(args) .. ")", "API")
153+
-- Trigger frame render if render-on-API mode is enabled
154+
if G.BALATROBOT_SHOULD_RENDER ~= nil then
155+
G.BALATROBOT_SHOULD_RENDER = true
156+
end
153157
func(args)
154158
end
155159
end

src/lua/settings.lua

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
local headless = os.getenv("BALATROBOT_HEADLESS") == "1"
33
local fast = os.getenv("BALATROBOT_FAST") == "1"
44
local audio = os.getenv("BALATROBOT_AUDIO") == "1"
5+
local render_on_api = os.getenv("BALATROBOT_RENDER_ON_API") == "1"
56
local port = os.getenv("BALATROBOT_PORT")
67
local host = os.getenv("BALATROBOT_HOST")
78

@@ -13,6 +14,7 @@ local config = {
1314
headless = headless,
1415
fast = fast,
1516
audio = audio,
17+
render_on_api = render_on_api,
1618
}
1719

1820
-- Apply Love2D patches for performance
@@ -182,8 +184,52 @@ local function configure_headless()
182184
sendInfoMessage("BalatroBot: Headless mode enabled - graphics rendering disabled")
183185
end
184186

187+
-- Configure on-demand rendering (render only when API calls are made)
188+
local function configure_render_on_api()
189+
if not config.render_on_api then
190+
return
191+
end
192+
193+
-- Global flag to trigger rendering
194+
G.BALATROBOT_SHOULD_RENDER = false
195+
196+
-- Store original rendering functions
197+
local original_draw = love.draw
198+
local original_present = love.graphics.present
199+
local did_render_this_frame = false
200+
201+
-- Replace love.draw to only render when flag is set
202+
---@diagnostic disable-next-line: duplicate-set-field
203+
love.draw = function()
204+
if G.BALATROBOT_SHOULD_RENDER then
205+
original_draw()
206+
did_render_this_frame = true
207+
G.BALATROBOT_SHOULD_RENDER = false
208+
else
209+
did_render_this_frame = false
210+
end
211+
end
212+
213+
-- Replace love.graphics.present to only present when rendering happened
214+
---@diagnostic disable-next-line: duplicate-set-field
215+
love.graphics.present = function()
216+
if did_render_this_frame then
217+
original_present()
218+
did_render_this_frame = false
219+
end
220+
end
221+
222+
sendInfoMessage("BalatroBot: Render-on-API mode enabled - frames only on API calls")
223+
end
224+
185225
-- Main setup function
186226
SETTINGS.setup = function()
227+
-- Validate mutually exclusive options
228+
if config.headless and config.render_on_api then
229+
sendErrorMessage("--headless and --render-on-api are mutually exclusive. Choose one rendering mode.", "SETTINGS")
230+
error("Configuration error: mutually exclusive rendering modes specified")
231+
end
232+
187233
G.BALATROBOT_PORT = port or "12346"
188234
G.BALATROBOT_HOST = host or "127.0.0.1"
189235

@@ -195,4 +241,7 @@ SETTINGS.setup = function()
195241

196242
-- Apply headless optimizations if needed
197243
configure_headless()
244+
245+
-- Apply render-on-API optimizations if needed
246+
configure_render_on_api()
198247
end

0 commit comments

Comments
 (0)