-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreplayManager.lua
175 lines (160 loc) · 5.6 KB
/
replayManager.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
local lume=require"lume"
local bit=require"bit"
local levelData = require "levelData"
local player = require "player"
local replayManager={}
replayManager.REPLAY_NUM_PER_PAGE=25
replayManager.PAGES=4
replayManager.MAX_NAME_LENGTH=20
local dir='replay'
love.filesystem.createDirectory(dir)
local function savePath(slot)
return dir..'/'..string.format('%03d',slot)..'.rpy'
end
function Hash64(input)
local hash_table = {}
local seed = 0xABCDEF -- Seed value to initialize the hashing process
-- Initialize the hash table with 64 default values
for i = 1, 64 do
hash_table[i] = (seed * i) % 256
end
-- Iterate through each character in the input string
for i = 1, #input do
local byte = string.byte(input, i)
local index = (i % 64) + 1
-- Use bitwise operations to modify the hash table
local temp = hash_table[index]
temp = bit.bxor(temp, byte)
temp = bit.rol(temp, 3) -- Rotate left 3 bits
temp = (temp + seed) % 256
hash_table[index] = temp
-- Update the seed based on the character value
seed = bit.bxor(seed, byte)
seed = bit.ror(seed, 5) -- Rotate right 5 bits
end
-- Further diffusion across the hash table
for i = 1, 64 do
local index = (i % 64) + 1
hash_table[i] = bit.bxor(hash_table[i], hash_table[index])
hash_table[i] = (hash_table[i] + seed) % 256
end
return hash_table
end
replayManager.getReplayData=function(slot,name)
local keyRecord=copy_table(Player.objects[1].keyRecord)
local seed=G.randomseed
local level=G.UIDEF.CHOOSE_LEVELS.chosenLevel
local scene=G.UIDEF.CHOOSE_LEVELS.chosenScene
local upgrades=G.save.upgrades
local time=Player.objects[1].realCreatedTime
local hash=Hash64(time..name..seed..level..scene)
for i = 1, #hash do
table.insert(keyRecord,hash[i])
end
local data={
keyRecord=keyRecord,
seed=seed,
level=level,
scene=scene,
upgrades=upgrades,
name=name,
time=time,
version=VERSION
}
return data
end
replayManager.saveReplay=function(slot,name)
local data=replayManager.getReplayData(slot,name)
local serialized = lume.serialize(data)
love.filesystem.write(savePath(slot), serialized)
replayManager.replays[slot]=replayManager.loadReplay(slot)
end
replayManager.loadReplay=function(slot)
local path=savePath(slot)
local file=love.filesystem.read(path)
if not file then
return false
end
local data = lume.deserialize(file)
local hash=Hash64(data.time..data.name..data.seed..data.level..data.scene)
local len=#data.keyRecord
for i=0,#hash-1 do
if data.keyRecord[len-i]~=hash[#hash-i]then
return false
end
table.remove(data.keyRecord,len-i)
end
return data
end
replayManager.runReplay=function(slot)
local replay=replayManager.loadReplay(slot)
if not replay then
SFX:play('cancel',true)
return
end
G.replay=replay
G.upgradesRef=G.save.upgrades
G.save.upgrades=replay.upgrades
G:enterLevel(replay.level,replay.scene)
-- seed restoring is in levelData
local player=Player.objects[1]
player:setReplaying()
player.keyRecord=replay.keyRecord
-- below is compat with old replay
if replay.time<'2024-12-10 21:20:00' then
player.shootInterval=1
player.shootRows.back.straight.damage=1
player.shootRows.side.straight.damage=1
player.shootRows.front.straight.damage=1
player.shootRows.front.homing.damage=1
player.shootRows.back.straight.num=player.shootRows.back.straight.num*2
end
local version=replay.version or '0.0.0'
player.version=version -- version<0.2.0.1 old graze effect is in player.lua
if version<'0.1.3' then
Circle.sizeFactor=4.5
Circle.spriteSizeFactor=1.0
end
if version<'0.2.1' then
player.grazeRadiusFactor=3.0
end
if version<'0.1.2' then
player.grazeRadiusFactor=1.5
end
end
-- note that replay param is used for pending (not saved yet) replay like when entering name. Other situations no need to input replay.
replayManager.getDescriptionString=function(slot,replay)
local slotWidth = 6 -- "No.012" (includes "No." prefix)
local nameWidth = 20 -- Reserve space for the name
local dateWidth = 19 -- "2023-10-11 18:30:20" (fixed format)
local levelSceneWidth = 6 -- e.g., "10-20"
local overallWidth=slotWidth+nameWidth+dateWidth+levelSceneWidth -- =51
if not replay then
replay=replayManager.replays[slot]
end
if not replay then
return string.format("No.%03d", slot)..' '..string.rep('-',overallWidth-slotWidth-1)
end
-- Format each component
local slotStr = string.format("No.%03d", slot)
local nameStr = string.format("%-" .. nameWidth .. "s", replay.name):sub(1, nameWidth) -- Pad or truncate name
local levelSceneStr = string.format("%d-%d", replay.level, replay.scene)
local dateStr = replay.time
-- Combine into a fixed-length string
local description = string.format("%-" .. slotWidth .. "s %-20s %s %-" .. levelSceneWidth .. "s",
slotStr, nameStr, dateStr, levelSceneStr)
return description
end
replayManager.monospacePrint=function(str,width,x,y)
for i=1,#str do
love.graphics.printf(str:sub(i,i),x+width*(i-1),y,width,'center')
end
end
replayManager.replays={}
replayManager.loadAll=function()
for i=1,replayManager.REPLAY_NUM_PER_PAGE*replayManager.PAGES do
replayManager.replays[i]=replayManager.loadReplay(i)
end
end
replayManager.loadAll()
return replayManager