Android build v1.1.5

This commit is contained in:
Warren H
2026-06-30 13:30:33 -04:00
parent 1797154726
commit f6d408f594
21 changed files with 763 additions and 254 deletions
+40 -18
View File
@@ -15,41 +15,63 @@ type FloatingCombatTextOptions = {
durationMs?: number
}
const FLOATING_TEXT_CLEANUP_INTERVAL_MS = 100
export function useFloatingCombatText<TText extends BasicFloatingCombatText>({
durationMs = 900,
}: FloatingCombatTextOptions = {}) {
const [floatingTexts, setFloatingTexts] = useState<TText[]>([])
const nextId = useRef(1)
const expirationsRef = useRef(new Map<number, number>())
const cleanupTimerRef = useRef<number | null>(null)
const clearCleanupTimer = useCallback(() => {
if (cleanupTimerRef.current === null) return
window.clearTimeout(cleanupTimerRef.current)
cleanupTimerRef.current = null
}, [])
const scheduleCleanup = useCallback(() => {
function scheduleNext() {
clearCleanupTimer()
let nextExpiry = Infinity
for (const expiresAt of expirationsRef.current.values()) {
nextExpiry = Math.min(nextExpiry, expiresAt)
}
if (!Number.isFinite(nextExpiry)) return
cleanupTimerRef.current = window.setTimeout(() => {
cleanupTimerRef.current = null
const now = performance.now()
let removed = false
for (const [id, expiresAt] of expirationsRef.current) {
if (expiresAt > now) continue
expirationsRef.current.delete(id)
removed = true
}
if (removed) {
setFloatingTexts((current) => current.filter((text) => expirationsRef.current.has(text.id)))
}
scheduleNext()
}, Math.max(0, nextExpiry - performance.now()))
}
scheduleNext()
}, [clearCleanupTimer])
const clearFloatingTexts = useCallback(() => {
clearCleanupTimer()
expirationsRef.current.clear()
setFloatingTexts([])
}, [])
}, [clearCleanupTimer])
const addFloatingText = useCallback((entry: Omit<TText, 'id'>) => {
if (entry.value <= 0) return
const id = nextId.current++
expirationsRef.current.set(id, performance.now() + durationMs)
setFloatingTexts((current) => appendFloatingText(current, { ...entry, id } as TText))
}, [durationMs])
scheduleCleanup()
}, [durationMs, scheduleCleanup])
useEffect(() => {
const timer = window.setInterval(() => {
const now = performance.now()
let removed = false
for (const [id, expiresAt] of expirationsRef.current) {
if (expiresAt > now) continue
expirationsRef.current.delete(id)
removed = true
}
if (!removed) return
setFloatingTexts((current) => current.filter((text) => expirationsRef.current.has(text.id)))
}, FLOATING_TEXT_CLEANUP_INTERVAL_MS)
return () => window.clearInterval(timer)
}, [])
useEffect(() => () => clearCleanupTimer(), [clearCleanupTimer])
const floatingTextsByMember = useMemo(
() => groupFloatingTextsByMember(floatingTexts),