Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ All notable changes to Light Engine will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.16-advanced.7] - 2026-10-04

### Fixed
- Quick keyboard taps now retain both press and release events until the next
update, so menu and pause actions are not lost between frames.
- Release archives exclude downloaded build icons and nested editor settings.

Android version code: 123.

## [0.1.16-advanced.6] - 2026-10-04

### Added
Expand Down
4 changes: 2 additions & 2 deletions lib/baton.lua
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ function Player:_pressControls(names, source, type, ...)
control.value = control.rawValue >= self.config.deadzone and control.rawValue or 0
control.down = true
control.pressed = true
control.released = false
control.released = control.debounce and control.released or false
control.debounce = true
for _, bind in pairs(control.pressBinds) do
bind(...)
Expand All @@ -338,7 +338,7 @@ function Player:_releaseControls(names, source, type, ...)
control.value = control.rawValue >= self.config.deadzone and control.rawValue or 0
control.downPrevious = true
control.down = false
control.pressed = false
control.pressed = control.debounce and control.pressed or false
control.released = true
control.debounce = true
for _, bind in pairs(control.releaseBinds) do
Expand Down
8 changes: 0 additions & 8 deletions loxel/input/keyboard.lua
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,6 @@ end
function Keyboard.onPressed(key)
Keyboard.loveInput.justPressed[key] = true
Keyboard.loveInput.pressed[key] = true
Keyboard.loveInput.justReleased[key] = nil
Keyboard.loveInput.released[key] = nil

if not table.find(invalidKeys, key) then
Expand All @@ -236,7 +235,6 @@ function Keyboard.onPressed(key)

Keyboard.input.justPressed[key] = true
Keyboard.input.pressed[key] = true
Keyboard.input.justReleased[key] = nil
Keyboard.input.released[key] = nil
end

Expand All @@ -251,21 +249,18 @@ function Keyboard.onPressed(key)
if not value then return end
Keyboard.justPressed[value] = true
Keyboard.pressed[value] = true
Keyboard.justReleased[value] = nil
Keyboard.released[value] = nil

Keyboard.onPress:dispatch(value)

Keyboard.justPressed.ANY = true
Keyboard.pressed.ANY = true
Keyboard.justReleased.ANY = nil
Keyboard.released.ANY = nil
end

function Keyboard.onReleased(key)
Keyboard.loveInput.justReleased[key] = true
Keyboard.loveInput.released[key] = true
Keyboard.loveInput.justPressed[key] = nil
Keyboard.loveInput.pressed[key] = nil

if not table.find(invalidKeys, key) then
Expand All @@ -281,7 +276,6 @@ function Keyboard.onReleased(key)

Keyboard.input.justReleased[key] = true
Keyboard.input.released[key] = true
Keyboard.input.justPressed[key] = nil
Keyboard.input.pressed[key] = nil
end

Expand All @@ -294,14 +288,12 @@ function Keyboard.onReleased(key)

local value = Keyboard.keyValues[key]
if not value then return end
Keyboard.justPressed[value] = nil
Keyboard.pressed[value] = nil
Keyboard.justReleased[value] = true
Keyboard.released[value] = true

Keyboard.onRelease:dispatch(value)

Keyboard.justPressed.ANY = nil
Keyboard.pressed.ANY = nil
Keyboard.justReleased.ANY = true
Keyboard.released.ANY = true
Expand Down
4 changes: 2 additions & 2 deletions project.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ return {
title = "Light Engine",
file = "Light Engine",
icon = "art/logo.png",
version = "0.1.16-advanced.6",
androidVersionCode = 122,
version = "0.1.16-advanced.7",
androidVersionCode = 123,
package = "com.zyn.lightengine",
width = 1280,
height = 720,
Expand Down
28 changes: 28 additions & 0 deletions tests/engine/core-utilities.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,34 @@ local function check(name, test)
end

function love.load()
check('keyboard taps keep both edges until the frame ends', function()
local keyboard = require 'loxel.input.keyboard'
keyboard.onPressed('a')
keyboard.onReleased('a')
assert(keyboard.justPressed.A and keyboard.justReleased.A, 'a quick tap must keep its press and release')
assert(keyboard.justPressed.ANY and keyboard.justReleased.ANY)
assert(keyboard.input.justPressed.a and keyboard.input.justReleased.a)
assert(keyboard.loveInput.justPressed.a and keyboard.loveInput.justReleased.a)
assert(not keyboard.pressed.A and keyboard.released.A)
keyboard.reset()
assert(not keyboard.justPressed.A and not keyboard.justReleased.A)
keyboard.onReleased('a')
keyboard.onPressed('a')
assert(keyboard.justPressed.A and keyboard.justReleased.A, 'a quick repress must keep both edges')
assert(keyboard.pressed.A and not keyboard.released.A)
keyboard.onReleased('a')
keyboard.reset()
end)
check('controls retain a tap delivered between updates', function()
local controls = require('lib.baton').new({controls = {accept = {'key:return'}}})
controls:onKeyPress('return')
controls:onKeyRelease('return')
controls:update()
assert(controls:pressed('accept'), 'a quick tap must reach the next update')
assert(controls:released('accept') and not controls:down('accept'))
controls:update()
assert(not controls:pressed('accept') and not controls:released('accept'), 'edges must last one update')
end)
check('table.move preserves offsets and overlapping ranges', function()
local source, destination = {'a', 'b', 'c', 'd'}, {}
assert(table.move(source, 2, 3, 1, destination) == destination)
Expand Down
3 changes: 2 additions & 1 deletion tests/test_game_archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ def test_build_caches_are_excluded_but_nested_runtime_mods_remain(self):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(b'original fixture')
junk = ['.ci/love/AppRun', '.superpowers/session.json',
'funkin/__pycache__/cached.pyc', 'assets/.DS_Store', 'old.apk.idsig']
'funkin/__pycache__/cached.pyc', 'assets/.DS_Store', 'old.apk.idsig',
'inputs/icon.ico', 'loxel/.vscode/settings.json']
for name in junk:
path = root / name
path.parent.mkdir(parents=True, exist_ok=True)
Expand Down
5 changes: 3 additions & 2 deletions tools/make_game_love.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"docs",
"examples",
"test-results",
"inputs",
}

# Files that only exist for development/CI.
Expand Down Expand Up @@ -66,7 +67,7 @@
def is_excluded(rel: str) -> bool:
"""`rel` is a POSIX style path relative to the repository root."""
parts = rel.split("/")
if "__pycache__" in parts:
if "__pycache__" in parts or ".vscode" in parts:
return True
# These names are root-level build/content directories. Matching every
# path component would also remove runtime modules such as funkin/ui/mods.
Expand Down Expand Up @@ -94,7 +95,7 @@ def collect_files() -> list[str]:
if not rel_dir:
dirs[:] = sorted(d for d in dirs if d not in SKIP_DIRS)
else:
dirs[:] = sorted(d for d in dirs if d != "__pycache__")
dirs[:] = sorted(d for d in dirs if d not in {"__pycache__", ".vscode"})
for name in sorted(files):
rel = f"{rel_dir}/{name}".lstrip("/") if rel_dir else name
if not is_excluded(rel):
Expand Down
Loading