Working 42.20 MP
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
local failures = 0
|
||||
|
||||
local function expect(condition, message)
|
||||
if not condition then
|
||||
failures = failures + 1
|
||||
io.stderr:write("FAIL: " .. message .. "\n")
|
||||
end
|
||||
end
|
||||
|
||||
isServer = function() return false end
|
||||
|
||||
local metrics = {
|
||||
offsets = 0,
|
||||
breaks = 0,
|
||||
adds = 0,
|
||||
hides = 0,
|
||||
postAttach = 0,
|
||||
scriptSwaps = 0,
|
||||
freeRolling = 0
|
||||
}
|
||||
local trace = {}
|
||||
local function record(event) trace[#trace + 1] = event end
|
||||
|
||||
local function script()
|
||||
return {
|
||||
getAttachmentById = function(_, id)
|
||||
if id == "trailer" or id == "trailerfront" then return {} end
|
||||
return nil
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
local acknowledgeAdd = true
|
||||
local function unlink(a, b)
|
||||
a.towing, a.towedBy = nil, nil
|
||||
b.towing, b.towedBy = nil, nil
|
||||
end
|
||||
|
||||
local function link(a, b)
|
||||
a.towing, a.towedBy = b, nil
|
||||
b.towing, b.towedBy = nil, a
|
||||
end
|
||||
|
||||
local function vehicle(id)
|
||||
local value = {
|
||||
id = id,
|
||||
towing = nil,
|
||||
towedBy = nil,
|
||||
script = script(),
|
||||
scriptName = "Base.TestVehicle",
|
||||
modData = {}
|
||||
}
|
||||
function value:getId() return self.id end
|
||||
function value:getScript() return self.script end
|
||||
function value:getScriptName() return self.scriptName end
|
||||
function value:getModData() return self.modData end
|
||||
function value:getVehicleTowing() return self.towing end
|
||||
function value:getVehicleTowedBy() return self.towedBy end
|
||||
function value:breakConstraint()
|
||||
metrics.breaks = metrics.breaks + 1
|
||||
record("break")
|
||||
local other = self.towing or self.towedBy
|
||||
if other then unlink(self, other) end
|
||||
end
|
||||
function value:addPointConstraint(player, other, attachmentA, attachmentB, localOnly)
|
||||
metrics.adds = metrics.adds + 1
|
||||
record("add")
|
||||
expect(player == nil, "rigid primitive must not impersonate a player")
|
||||
expect(attachmentA == "trailer" and attachmentB == "trailerfront",
|
||||
"rigid primitive must preserve selected attachment IDs")
|
||||
expect(localOnly == true, "rigid primitive must create the client-local rigid constraint")
|
||||
if acknowledgeAdd then link(self, other) end
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
TowBarMod = {
|
||||
Utils = {
|
||||
updateAttachmentsForRigidTow = function(a, b, attachmentA, attachmentB)
|
||||
metrics.offsets = metrics.offsets + 1
|
||||
expect(a ~= nil and b ~= nil, "rigid offset update must receive both vehicles")
|
||||
expect(attachmentA == "trailer" and attachmentB == "trailerfront",
|
||||
"rigid offset update must receive the selected endpoints")
|
||||
end
|
||||
},
|
||||
Hook = {
|
||||
applyFreeRollingTowState = function(vehicle)
|
||||
metrics.freeRolling = metrics.freeRolling + 1
|
||||
record("free")
|
||||
expect(vehicle ~= nil, "rigid primitive must receive the towed vehicle for free-roll setup")
|
||||
end,
|
||||
setVehicleScriptWithTowBarHidden = function(vehicle, scriptName)
|
||||
metrics.hides = metrics.hides + 1
|
||||
metrics.scriptSwaps = metrics.scriptSwaps + 1
|
||||
vehicle.scriptName = scriptName
|
||||
record("script:" .. tostring(scriptName))
|
||||
expect(vehicle ~= nil,
|
||||
"rigid primitive must receive a vehicle for each hidden script swap")
|
||||
end,
|
||||
setVehiclePostAttach = function(player, vehicle, towingVehicle)
|
||||
metrics.postAttach = metrics.postAttach + 1
|
||||
record("post")
|
||||
expect(player == nil and vehicle ~= nil and towingVehicle ~= nil,
|
||||
"rigid primitive must restore post-attach state after acknowledgement")
|
||||
expect(vehicle:getScriptName() == "Base.TestVehicle",
|
||||
"rigid primitive must restore the real script before post-attach finalization")
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
dofile("42.20/media/lua/client/TowBar/RigidTow.lua")
|
||||
|
||||
expect(TowBarMod.RigidTow ~= nil and type(TowBarMod.RigidTow.attach) == "function",
|
||||
"production rigid module must expose attach")
|
||||
|
||||
-- First attach with no physical relation uses the exact rigid path once.
|
||||
local a, b = vehicle(101), vehicle(102)
|
||||
trace = {}
|
||||
local attached = TowBarMod.RigidTow.attach(a, b, "trailer", "trailerfront")
|
||||
expect(attached == true, "acknowledged initial rigid add must succeed")
|
||||
expect(a:getVehicleTowing() == b and b:getVehicleTowedBy() == a,
|
||||
"acknowledged rigid add must leave an exact reciprocal relation")
|
||||
expect(metrics.offsets == 1 and metrics.adds == 1 and metrics.breaks == 0,
|
||||
"initial rigid add must update offsets and add once without a needless break")
|
||||
expect(metrics.scriptSwaps == 2 and metrics.postAttach == 1,
|
||||
"successful rigid add must select the fake script and restore the real script exactly once")
|
||||
expect(table.concat(trace, ",") == "free,script:notTowingA_Trailer,add,script:Base.TestVehicle,post",
|
||||
"initial rigid sequence must be free-roll, fake script, local add, real script, then post-attach")
|
||||
|
||||
-- A restored native relation is replaced inside this primitive. The lifecycle
|
||||
-- controller must not grow its own second copy of this physics sequence.
|
||||
local restoredA, restoredB = vehicle(201), vehicle(202)
|
||||
link(restoredA, restoredB)
|
||||
local beforeOffsets, beforeAdds = metrics.offsets, metrics.adds
|
||||
local beforeBreaks, beforePost = metrics.breaks, metrics.postAttach
|
||||
trace = {}
|
||||
attached = TowBarMod.RigidTow.attach(restoredA, restoredB, "trailer", "trailerfront")
|
||||
expect(attached == true, "restored native relation must be replaced by rigid mechanics")
|
||||
expect(metrics.offsets == beforeOffsets + 1 and metrics.adds == beforeAdds + 1,
|
||||
"native replacement must update offsets and add one rigid constraint")
|
||||
expect(metrics.breaks == beforeBreaks + 1,
|
||||
"native replacement must break the exact old pair once")
|
||||
expect(metrics.postAttach == beforePost + 1,
|
||||
"native replacement must run post-attach only after the new link exists")
|
||||
expect(table.concat(trace, ",") == "break,free,script:notTowingA_Trailer,add,script:Base.TestVehicle,post",
|
||||
"native replacement sequence must break, free-roll, use the fake script, add, restore the real script, then finalize")
|
||||
|
||||
-- A link to a different vehicle is never collateral damage.
|
||||
local conflictA, expectedB, unrelated = vehicle(301), vehicle(302), vehicle(399)
|
||||
link(conflictA, unrelated)
|
||||
local beforeConflictBreaks, beforeConflictAdds = metrics.breaks, metrics.adds
|
||||
attached = TowBarMod.RigidTow.attach(conflictA, expectedB, "trailer", "trailerfront")
|
||||
expect(attached == false, "conflicting physical link must reject rigid attachment")
|
||||
expect(metrics.breaks == beforeConflictBreaks and metrics.adds == beforeConflictAdds,
|
||||
"conflicting physical link must not break or layer another constraint")
|
||||
|
||||
-- Invalid endpoints are rejected before modifying a valid existing pair.
|
||||
local missingA, missingB = vehicle(351), vehicle(352)
|
||||
link(missingA, missingB)
|
||||
local beforeMissingBreaks, beforeMissingAdds = metrics.breaks, metrics.adds
|
||||
attached = TowBarMod.RigidTow.attach(missingA, missingB, "missing", "trailerfront")
|
||||
expect(attached == false, "missing attachment must reject rigid attachment")
|
||||
expect(metrics.breaks == beforeMissingBreaks and metrics.adds == beforeMissingAdds,
|
||||
"missing attachment must not break the existing pair or attempt an add")
|
||||
|
||||
-- In multiplayer Java/Bullet may accept the local constraint before the Lua
|
||||
-- reciprocal getters update. Submission is success; waiting for those getters
|
||||
-- here strands an already-streamed pair with only its visual state applied.
|
||||
local delayedA, delayedB = vehicle(401), vehicle(402)
|
||||
acknowledgeAdd = false
|
||||
local beforeDelayedPost = metrics.postAttach
|
||||
attached = TowBarMod.RigidTow.attach(delayedA, delayedB, "trailer", "trailerfront")
|
||||
expect(attached == true, "submitted rigid add must tolerate delayed multiplayer getters")
|
||||
expect(metrics.postAttach == beforeDelayedPost + 1,
|
||||
"delayed multiplayer getters must not block post-attach restoration")
|
||||
|
||||
if failures > 0 then os.exit(1) end
|
||||
print("PASS: single rigid-tow contract preserves exact-pair mechanics and delayed MP submission")
|
||||
Reference in New Issue
Block a user