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
4 changes: 2 additions & 2 deletions client/src/ChallengeMode.lua
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ function ChallengeMode:onMatchEnded(match)
-- so always record the result, even if it may have been an abort
local gameTime = 0
local stackEngine = match.stacks[1].engine
if stackEngine ~= nil and stackEngine.game_stopwatch then
gameTime = stackEngine.game_stopwatch
if stackEngine ~= nil and stackEngine.stopWatch then
gameTime = stackEngine.stopWatch
end
self:recordStageResult(winners, gameTime)

Expand Down
1 change: 0 additions & 1 deletion client/src/ChallengeModePlayer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ local ChallengeModePlayerStack = require("client.src.ChallengeModePlayerStack")
---@class ChallengeModePlayer : MatchParticipant
---@field usedCharacterIds string[] array of character ids that have already been used during the life time of the player
---@field settings ChallengeModePlayerSettings

local ChallengeModePlayer = class(
function(self, playerNumber)
self.name = "Challenger"
Expand Down
4 changes: 2 additions & 2 deletions client/src/ClientMatch.lua
Original file line number Diff line number Diff line change
Expand Up @@ -539,8 +539,8 @@ function ClientMatch:drawTimer()
-- Draw the timer for time attack
local frames = 0
local stack = self.stacks[1]
if stack ~= nil and stack.engine.game_stopwatch ~= nil and tonumber(stack.engine.game_stopwatch) ~= nil then
frames = stack.engine.game_stopwatch
if stack ~= nil and stack.engine.stopWatch ~= nil and tonumber(stack.engine.stopWatch) ~= nil then
frames = stack.engine.stopWatch
end

if self.engine.timeLimit then
Expand Down
1 change: 1 addition & 0 deletions client/src/MatchParticipant.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ local ModController = require("client.src.mods.ModController")
---@field ready boolean if the participant is ready to start the game (wants to and actually is)
---@field human boolean if the participant is a human
---@field isLocal boolean if the participant is controlled by a local player
---@field playerNumber integer the (external) id for the player within the room; used to assign server messages to the correct player when spectating
---@field stack ClientStack?

-- a match participant represents the minimum spec for a what constitutes a "player" in a battleRoom / match
Expand Down
1 change: 0 additions & 1 deletion client/src/PlayerStack.lua
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,6 @@ function PlayerStack:onRollback(engine)

-- to fool Match without having to wrap everything into getters
self.clock = engine.clock
self.game_stopwatch = engine.game_stopwatch

--prof.push("rollback copy analytics")
self.analytic:rollbackToFrame(self.clock)
Expand Down
27 changes: 18 additions & 9 deletions client/src/PuzzleSet.lua
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ function PuzzleSet.loadV1(setName, puzzleSetData)
for _, puzzleData in pairs(puzzleSetData) do
if type(puzzleData) == "table" and #puzzleData >= 2 and type(puzzleData[1]) == "string" and type(puzzleData[2]) == "number" then
local args = {
puzzleType = "moves",
startTiming = "countdown",
puzzleType = Puzzle.PUZZLE_TYPES.moves,
startTiming = Puzzle.START_TIMINGS.countdown,
moves = puzzleData[2],
stack = puzzleData[1]
}
Expand All @@ -198,7 +198,7 @@ function PuzzleSet.loadV2(puzzleSetData)
for _, puzzleData in pairs(puzzleSetData[PuzzleSet.PUZZLE_SET_PROPERTY.PUZZLES]) do
local args = {
puzzleType = puzzleData[Puzzle.PUZZLE_PROPERTY.TYPE],
startTiming = puzzleData["Do Countdown"] and "countdown" or "immediately",
startTiming = puzzleData["Do Countdown"] and Puzzle.START_TIMINGS.countdown or Puzzle.START_TIMINGS.immediately,
moves = puzzleData[Puzzle.PUZZLE_PROPERTY.MOVES],
stack = puzzleData[Puzzle.PUZZLE_PROPERTY.STACK],
stopTime = puzzleData[Puzzle.PUZZLE_PROPERTY.STOP],
Expand Down Expand Up @@ -263,9 +263,10 @@ function PuzzleSet.loadV3(puzzleSetData)
local puzzleSet = PuzzleSet(puzzleSetName, puzzleSetDescription, {}, {})

for _, puzzleData in pairs(puzzleSetData[PuzzleSet.PUZZLE_SET_PROPERTY.PUZZLES] or {}) do
---@type string
local puzzleTypeValue = puzzleData[Puzzle.PUZZLE_PROPERTY.TYPE]
local args = {
puzzleType = puzzleData[Puzzle.PUZZLE_PROPERTY.TYPE],
startTiming = puzzleData[Puzzle.PUZZLE_PROPERTY.START_TIMING],
puzzleType = string.lower(puzzleTypeValue),
moves = puzzleData[Puzzle.PUZZLE_PROPERTY.MOVES],
stack = puzzleData[Puzzle.PUZZLE_PROPERTY.STACK],
stopTime = puzzleData[Puzzle.PUZZLE_PROPERTY.STOP],
Expand All @@ -276,10 +277,18 @@ function PuzzleSet.loadV3(puzzleSetData)
helpDescription = puzzleData[Puzzle.PUZZLE_PROPERTY.HELP_DESCRIPTION]
}
if puzzleData[Puzzle.PUZZLE_PROPERTY.CURSOR_START_LEFT] then
args.cursorStartLeft = {
row = puzzleData[Puzzle.PUZZLE_PROPERTY.CURSOR_START_LEFT][Puzzle.CURSOR_PROPERTY.ROW],
column = puzzleData[Puzzle.PUZZLE_PROPERTY.CURSOR_START_LEFT][Puzzle.CURSOR_PROPERTY.COLUMN]
}
args.cursorStartLeft = {row = puzzleData[Puzzle.PUZZLE_PROPERTY.CURSOR_START_LEFT].Row, column = puzzleData[Puzzle.PUZZLE_PROPERTY.CURSOR_START_LEFT].Column}
end
if puzzleData[Puzzle.PUZZLE_PROPERTY.START_TIMING] then
if puzzleData[Puzzle.PUZZLE_PROPERTY.START_TIMING] == "First Swap" then
args.startTiming = Puzzle.START_TIMINGS.firstSwap
elseif puzzleData[Puzzle.PUZZLE_PROPERTY.START_TIMING] == "First Input" then
args.startTiming = Puzzle.START_TIMINGS.firstInput
elseif puzzleData[Puzzle.PUZZLE_PROPERTY.START_TIMING] == "Countdown" then
args.startTiming = Puzzle.START_TIMINGS.countdown
elseif puzzleData[Puzzle.PUZZLE_PROPERTY.START_TIMING] == "Immediately" then
args.startTiming = Puzzle.START_TIMINGS.immediately
end
end

local puzzle = Puzzle(args)
Expand Down
4 changes: 3 additions & 1 deletion client/src/debug/DebugSettings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,9 @@ function DebugSettings.setShowRuntimeGraph(value)
DebugSettings.set("showRuntimeGraph", value)
end

-- Sets the VS frames behind value
--- Sets the VS frames behind value <br>
--- Careful with setting this too high when using this with replays: if stack 1 is the losing one it can happen that they never receive the garbage that topped them out
--- because the second stack does not simulate far enough to send it, causing the replay to get stuck
---@param value number
function DebugSettings.setVSFramesBehind(value)
DebugSettings.set("vsFramesBehind", value)
Expand Down
2 changes: 1 addition & 1 deletion client/src/graphics/ChallengeModeTimeSplitsUIElement.lua
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function ChallengeModeTimeSplitsUIElement:drawTimeSplits()
local currentStageTime = time
local isCurrentStage = (self.currentStageIndex and i == self.currentStageIndex)
if isCurrentStage and self.challengeMode.match and not self.challengeMode.match.ended then
currentStageTime = currentStageTime + (self.challengeMode.match.stacks[1].engine.game_stopwatch or 0)
currentStageTime = currentStageTime + (self.challengeMode.match.stacks[1].engine.stopWatch or 0)
end
totalTime = totalTime + currentStageTime

Expand Down
4 changes: 2 additions & 2 deletions client/src/scenes/PortraitGame.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ PortraitGame.name = "PortraitGame"
local function getTimer(match)
local frames = 0
local stack = match.stacks[1]
if stack ~= nil and stack.engine.game_stopwatch ~= nil and tonumber(stack.engine.game_stopwatch) ~= nil then
frames = stack.engine.game_stopwatch
if stack ~= nil and stack.engine.stopWatch ~= nil and tonumber(stack.engine.stopWatch) ~= nil then
frames = stack.engine.stopWatch
end

if match.engine.timeLimit then
Expand Down
20 changes: 20 additions & 0 deletions client/tests/PuzzleSetTests.lua
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,25 @@ function PuzzleSetTests.testExactJSONFormatting()
assert(prettified == expected, "JSON formatting should match exactly")
end

function PuzzleSetTests.testLoadV3WithoutStartTiming()
-- Test that loading a v3 puzzle without StartTiming works
local puzzleSetData = {
["Set Name"] = "Test Set",
["Description"] = "Test description",
["Puzzles"] = {
{
["Puzzle Type"] = "moves",
["Moves"] = 5,
["Stack"] = "1254216999999952"
}
}
}

local result = PuzzleSet.loadV3(puzzleSetData)
assert(result ~= nil, "Should have loaded puzzle set")
assert(#result.puzzles == 1, "Should have one puzzle")
end

-- Run the tests
PuzzleSetTests.updatePuzzleValid()
PuzzleSetTests.generateSaveDataValid()
Expand All @@ -208,5 +227,6 @@ PuzzleSetTests.generateSaveDataWithOptionalFields()
PuzzleSetTests.testJSONValidityRequirement1()
PuzzleSetTests.testUnchangedPuzzlePreservationRequirement3()
PuzzleSetTests.testExactJSONFormatting()
PuzzleSetTests.testLoadV3WithoutStartTiming()

return PuzzleSetTests
12 changes: 6 additions & 6 deletions common/compatibility/LegacyPanelSource.lua
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ function LegacyPanelSource:clone(stack)
return source
end

function LegacyPanelSource:saveForRollback(frame)
function LegacyPanelSource:saveForRollback(clock)
local copy = self.rollbackBuffer:getOldest()

if not copy then
Expand All @@ -209,11 +209,11 @@ function LegacyPanelSource:saveForRollback(frame)
copy.panelGenCount = self.panelGenCount
copy.garbageGenCount = self.garbageGenCount

self.rollbackBuffer:saveCopy(frame, copy)
self.rollbackBuffer:saveCopy(clock, copy)
end

function LegacyPanelSource:rollbackToFrame(frame)
local copy = self.rollbackBuffer:rollbackToFrame(frame)
function LegacyPanelSource:rollbackToFrame(clock)
local copy = self.rollbackBuffer:rollbackToFrame(clock)

if not copy then
error("Could not rollback LegacyPanelSource")
Expand All @@ -225,8 +225,8 @@ function LegacyPanelSource:rollbackToFrame(frame)
self.garbageGenCount = copy.garbageGenCount
end

function LegacyPanelSource:rewindToFrame(frame)
self:rollbackToFrame(frame)
function LegacyPanelSource:rewindToFrame(clock)
self:rollbackToFrame(clock)
end

return LegacyPanelSource
36 changes: 18 additions & 18 deletions common/engine/AttackEngine.lua
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ AttackPattern =
---@field treatMetalAsCombo boolean whether the metal garbage is treated the same as combo garbage (aka they can mix)
---@field attackPatterns AttackPattern[] The array of AttackPattern objects this engine will run through.
---@field attackSettings table The format for serializing AttackPattern information
---@field stopwatch integer The stopwatch to control the continuity of the sending process
---@field stopWatch integer The stopWatch to control the continuity of the sending process
---@field outgoingGarbage GarbageQueue The garbage queue attacks are added to
local AttackEngine = class(
function(self, attackSettings, garbageQueue)
Expand All @@ -50,7 +50,7 @@ local AttackEngine = class(
self:addAttackPatternsFromTable(attackSettings.attackPatterns)
self.attackSettings = attackSettings

self.stopwatch = 0
self.stopWatch = 0

self.outgoingGarbage = garbageQueue
-- to ensure correct behaviour according to the pattern definition
Expand Down Expand Up @@ -85,7 +85,7 @@ end
-- Adds an attack pattern that happens repeatedly on a timer.
---@param width integer? the width of the garbage block in columns
---@param height integer? the height of the garbage block in rows
---@param start integer the stopwatch frame these attacks should start being sent
---@param start integer the stopWatch frame these attacks should start being sent
---@param metal boolean? if this is a metal block
---@param chain boolean? if this is a chain attack
function AttackEngine.addAttackPattern(self, width, height, start, metal, chain)
Expand All @@ -94,7 +94,7 @@ function AttackEngine.addAttackPattern(self, width, height, start, metal, chain)
self.attackPatterns[#self.attackPatterns + 1] = attackPattern
end

---@param chainEnd integer the stopwatch frame the ongoing chain is being finalized
---@param chainEnd integer the stopWatch frame the ongoing chain is being finalized
function AttackEngine.addEndChainPattern(self, chainEnd)
local attackPattern = AttackPattern(0, 0, self.delayBeforeStart + chainEnd, false, false, true)
self.attackPatterns[#self.attackPatterns + 1] = attackPattern
Expand All @@ -117,21 +117,21 @@ function AttackEngine.run(self)
-- that the recipient is stalling acceptance so we shouldn't push more inside
if self.disableQueueLimit or self.outgoingGarbage.transitTimers:len() <= 6 then
for i = 1, #self.attackPatterns do
if self.stopwatch >= self.attackPatterns[i].startTime then
local difference = self.stopwatch - self.attackPatterns[i].startTime
if self.stopWatch >= self.attackPatterns[i].startTime then
local difference = self.stopWatch - self.attackPatterns[i].startTime
local remainder = difference % totalAttackTimeBeforeRepeat
if remainder == 0 then
if self.attackPatterns[i].endsChain then
if not self.outgoingGarbage.currentChain then
break
end
self.outgoingGarbage:finalizeCurrentChain(self.stopwatch)
self.outgoingGarbage:finalizeCurrentChain(self.stopWatch)
else
local garbage = self.attackPatterns[i].garbage
if garbage.isChain then
self.outgoingGarbage:addChainLink(self.stopwatch, math.random(1, 11), math.random(1, 6))
self.outgoingGarbage:addChainLink(self.stopWatch, math.random(1, 11), math.random(1, 6))
else
garbage.frameEarned = self.stopwatch
garbage.frameEarned = self.stopWatch
-- we need a coordinate for the origin of the attack animation
garbage.rowEarned = math.random(1, 11)
garbage.colEarned = math.random(1, 6)
Expand All @@ -147,21 +147,21 @@ function AttackEngine.run(self)
end
end

self.stopwatch = self.stopwatch + 1
self.stopWatch = self.stopWatch + 1
end

function AttackEngine:saveForRollback(frame)
self.outgoingGarbage:saveForRollback(frame)
function AttackEngine:saveForRollback(stopWatch)
self.outgoingGarbage:saveForRollback(stopWatch)
end

function AttackEngine:rollbackToFrame(frame)
self.outgoingGarbage:rollbackToFrame(frame)
self.stopwatch = frame
function AttackEngine:rollbackToFrame(stopWatch)
self.outgoingGarbage:rollbackToFrame(stopWatch)
self.stopWatch = stopWatch
end

function AttackEngine:rewindToFrame(frame)
self.outgoingGarbage:rewindToFrame(frame)
self.stopwatch = frame
function AttackEngine:rewindToFrame(stopWatch)
self.outgoingGarbage:rewindToFrame(stopWatch)
self.stopWatch = stopWatch
end

return AttackEngine
22 changes: 11 additions & 11 deletions common/engine/BaseStack.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ local MatchRules = require("common.data.MatchRules")
---@field is_local boolean effectively if the Stack is receiving its inputs via local input
---@field framesBehindArray integer[] Records how far behind the stack was at each match clock time
---@field framesBehind integer How far behind the stack is at the current Match clock time
---@field clock integer how many times run has been called
---@field game_stopwatch integer how many times the simulation has run
---@field game_stopwatch_running boolean if the stack is simulating during runs
---@field clock integer how many times run has been called; this is equivalent to how many inputs have been processed;<br>This is the chief timer to measure synchronicity and the driver of rollback and inputs
---@field stopWatch integer how many times the game physics have run; unlike a clock and just like a stopWatch this frame timer only runs when the simulation is running
---@field stopWatchIsRunning boolean if the stack is running the game physics during runs
---@field game_over_clock integer What the clock time was when the Stack went game over
---@field do_countdown boolean if the stack is performing a countdown at the start of the match
---@field do_countdown boolean if the stack is currently performing a countdown / will perform a countdown at the start of the match;<br> this is state, the value will change at the end of countdown
---@field countdown_timer boolean? ephemeral timer used for tracking countdown progress at the start of the game
---@field outgoingGarbage GarbageQueue
---@field incomingGarbage GarbageQueue
Expand Down Expand Up @@ -61,8 +61,8 @@ function(self, args)
self.framesBehindArray = {}
self.framesBehind = 0
self.clock = 0
self.game_stopwatch = 0
self.game_stopwatch_running = true
self.stopWatch = 0
self.stopWatchIsRunning = true
self.game_over_clock = -1 -- the exact clock frame the stack lost, -1 while alive
Signal.turnIntoEmitter(self)
self:createSignal("gameOver")
Expand Down Expand Up @@ -116,7 +116,7 @@ end
---@param doCountdown boolean
function BaseStack:setCountdown(doCountdown)
self.do_countdown = doCountdown
self.game_stopwatch_running = not self.do_countdown
self.stopWatchIsRunning = not self.do_countdown
end

---@param maxRunsPerFrame integer
Expand Down Expand Up @@ -161,15 +161,15 @@ function BaseStack:saveForRollback()
error("did not implement saveForRollback")
end

---@param frame integer the frame to rollback to if possible
---@param clock integer the frame to rollback to if possible
---@return boolean success if rolling back succeeded
function BaseStack:rollbackToFrame(frame)
function BaseStack:rollbackToFrame(clock)
error("did not implement rollbackToFrame")
end

---@param frame integer the frame to rewind to if possible
---@param clock integer the frame to rewind to if possible
---@return boolean success if rewinding succeeded
function BaseStack:rewindToFrame(frame)
function BaseStack:rewindToFrame(clock)
error("did not implement rewindToFrame")
end

Expand Down
22 changes: 11 additions & 11 deletions common/engine/GarbageQueue.lua
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,13 @@ function GarbageQueue:saveForRollback(frame)
self.rollbackBuffer:saveCopy(frame, copy)
end

---@param frame integer
function GarbageQueue:rollbackToFrame(frame)
assert(self.rollbackBuffer, "Attempted to rollback garbage queue to frame " .. frame .. " but no rollback buffer has been kept")
---@param stopWatch integer
function GarbageQueue:rollbackToFrame(stopWatch)
assert(self.rollbackBuffer, "Attempted to rollback garbage queue to frame " .. stopWatch .. " but no rollback buffer has been kept")

local copy = self.rollbackBuffer:rollbackToFrame(frame)
local copy = self.rollbackBuffer:rollbackToFrame(stopWatch)

assert(copy, "Attempted to rollback garbage queue to frame " .. frame .. " but no rollback copy was available")
assert(copy, "Attempted to rollback garbage queue to frame " .. stopWatch .. " but no rollback copy was available")

self.stagedGarbage = copy.stagedGarbage
self.currentChain = copy.currentChain
Expand All @@ -220,20 +220,20 @@ function GarbageQueue:rollbackToFrame(frame)
-- this may not universally work for multiplayer with more than 2 players
for i = self.transitTimers.last, self.transitTimers.first, -1 do
local transitFrame = self.transitTimers[i]
if transitFrame >= frame + GARBAGE_DELAY_LAND_TIME then
if transitFrame >= stopWatch + GARBAGE_DELAY_LAND_TIME then
self.garbageInTransit[transitFrame] = nil
self.transitTimers.last = self.transitTimers.last - 1
end
end
end

---@param frame integer
function GarbageQueue:rewindToFrame(frame)
assert(self.rollbackBuffer, "Attempted to rewind garbage queue to frame " .. frame .. " but no rollback buffer has been kept")
---@param stopWatch integer
function GarbageQueue:rewindToFrame(stopWatch)
assert(self.rollbackBuffer, "Attempted to rewind garbage queue to frame " .. stopWatch .. " but no rollback buffer has been kept")

local copy = self.rollbackBuffer:rollbackToFrame(frame)
local copy = self.rollbackBuffer:rollbackToFrame(stopWatch)

assert(copy, "Attempted to rewind garbage queue to frame " .. frame .. " but no rollback copy was available")
assert(copy, "Attempted to rewind garbage queue to frame " .. stopWatch .. " but no rollback copy was available")

self.stagedGarbage = copy.stagedGarbage
self.currentChain = copy.currentChain
Expand Down
Loading