isaacscript 2.0.14-dev.1 → 2.0.14-dev.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/file-templates/dynamic/README.md +3 -0
- package/file-templates/dynamic/gitignore +144 -0
- package/file-templates/dynamic/main.ts +19 -0
- package/file-templates/dynamic/metadata.vdf +6 -0
- package/file-templates/dynamic/metadata.xml +8 -0
- package/file-templates/dynamic/package.json +20 -0
- package/file-templates/static/.cspell.json.template +21 -0
- package/file-templates/static/.env_template +2 -0
- package/file-templates/static/.eslintrc.js +24 -0
- package/file-templates/static/.gitattributes +9 -0
- package/file-templates/static/.github/workflows/ci.yml +53 -0
- package/file-templates/static/.prettierignore +14 -0
- package/file-templates/static/.prettierrc.js +42 -0
- package/file-templates/static/.vscode/extensions.json +10 -0
- package/file-templates/static/.vscode/settings.json +79 -0
- package/file-templates/static/LICENSE +674 -0
- package/file-templates/static/build.sh +15 -0
- package/file-templates/static/check-orphaned-words.sh +58 -0
- package/file-templates/static/lint.sh +39 -0
- package/file-templates/static/nuke.sh +18 -0
- package/file-templates/static/plugins/addCrashDebugStatements.ts +40 -0
- package/file-templates/static/plugins/addIsaacScriptCommentHeader.ts +37 -0
- package/file-templates/static/plugins/noExtendedEnums.ts +69 -0
- package/file-templates/static/publish.sh +10 -0
- package/file-templates/static/run.sh +10 -0
- package/file-templates/static/src/bundleEntry.ts +10 -0
- package/file-templates/static/tsconfig.eslint.json +11 -0
- package/file-templates/static/tsconfig.json +33 -0
- package/file-templates/static/update.sh +21 -0
- package/file-templates/static-alt/.prettierignore-base +5 -0
- package/file-templates/static-alt/.prettierrc-base.js +30 -0
- package/file-templates/static-alt/.vscode/extensions-typescript.json +9 -0
- package/file-templates/static-alt/.vscode/settings-typescript.json +66 -0
- package/file-templates/static-alt/check-file-updates.sh +67 -0
- package/isaacscript-watcher/.luacheckrc +96 -0
- package/isaacscript-watcher/README.md +8 -0
- package/isaacscript-watcher/main.lua +270 -0
- package/isaacscript-watcher/metadata.xml +7 -0
- package/isaacscript-watcher/resources/gfx/logo.anm2 +27 -0
- package/isaacscript-watcher/resources/gfx/logo.png +0 -0
- package/package.json +1 -1
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
-- Includes
|
|
2
|
+
local json = require("json")
|
|
3
|
+
|
|
4
|
+
-- Constants
|
|
5
|
+
local MOD_NAME = "isaacscript-watcher"
|
|
6
|
+
local RESTART_GAME_ON_RECOMPILATION = true
|
|
7
|
+
local FRAMES_BEFORE_DISCONNECTED = 2 * 60 -- 2 seconds
|
|
8
|
+
local FRAMES_BEFORE_TEXT_FADE = 2 * 60 -- 2 seconds
|
|
9
|
+
local SPRITE_BOTTOM_RIGHT_OFFSET = Vector(-35, -60)
|
|
10
|
+
-- (enough so that it does not overlap with a pocket active + 2 pocket items)
|
|
11
|
+
|
|
12
|
+
-- Mod variables
|
|
13
|
+
local saveData = {} -- An array of message objects.
|
|
14
|
+
local restartFrame = 0
|
|
15
|
+
local messageArray = {}
|
|
16
|
+
local frameOfLastMsg = 0
|
|
17
|
+
local frameOfLastSuccessfulLoad = 0
|
|
18
|
+
local game = Game()
|
|
19
|
+
local font = Font()
|
|
20
|
+
font:Load("font/pftempestasevencondensed.fnt") -- A vanilla font good for this kind of text.
|
|
21
|
+
local connected = false
|
|
22
|
+
local sprite = nil
|
|
23
|
+
|
|
24
|
+
local IsaacScriptWatcher = RegisterMod("IsaacScript Watcher", 1)
|
|
25
|
+
|
|
26
|
+
-- On mod initialization, nuke the "save#.dat" folder to get rid of old messages that might be left
|
|
27
|
+
-- there from IsaacScript.
|
|
28
|
+
IsaacScriptWatcher:SaveData("")
|
|
29
|
+
|
|
30
|
+
local function pushMessageArray(msg)
|
|
31
|
+
frameOfLastMsg = Isaac.GetFrameCount()
|
|
32
|
+
|
|
33
|
+
messageArray[#messageArray + 1] = msg
|
|
34
|
+
if #messageArray > 10 then
|
|
35
|
+
-- We only want to show 10 messages at a time.
|
|
36
|
+
table.remove(messageArray, 1)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
local function getScreenBottomRightPos()
|
|
41
|
+
local screenWidth = Isaac.GetScreenWidth();
|
|
42
|
+
local screenHeight = Isaac.GetScreenHeight();
|
|
43
|
+
|
|
44
|
+
return Vector(screenWidth, screenHeight)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
-- ModCallbacks.MC_POST_RENDER (2)
|
|
48
|
+
function IsaacScriptWatcher:PostRender()
|
|
49
|
+
-- Don't do anything while fading in to a new run to prevent crashes.
|
|
50
|
+
if game:GetFrameCount() < 1 then
|
|
51
|
+
return
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
IsaacScriptWatcher:RenderSprite()
|
|
55
|
+
IsaacScriptWatcher:RenderText()
|
|
56
|
+
IsaacScriptWatcher:LoadSaveDat()
|
|
57
|
+
IsaacScriptWatcher:CheckInput()
|
|
58
|
+
IsaacScriptWatcher:CheckRestart()
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
function IsaacScriptWatcher:RenderSprite()
|
|
62
|
+
-- Determine if IsaacScript is connected or not.
|
|
63
|
+
local frameCount = Isaac.GetFrameCount()
|
|
64
|
+
connected = frameCount - frameOfLastSuccessfulLoad <= FRAMES_BEFORE_DISCONNECTED
|
|
65
|
+
|
|
66
|
+
-- Set the sprite
|
|
67
|
+
if connected then
|
|
68
|
+
if sprite == nil then
|
|
69
|
+
sprite = Sprite()
|
|
70
|
+
sprite:Load("gfx/logo.anm2", true)
|
|
71
|
+
sprite:SetFrame("Default", 0)
|
|
72
|
+
end
|
|
73
|
+
else
|
|
74
|
+
if sprite ~= nil then
|
|
75
|
+
sprite = nil
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
-- Render it
|
|
80
|
+
if sprite ~= nil then
|
|
81
|
+
local bottomRightPos = getScreenBottomRightPos()
|
|
82
|
+
local position = bottomRightPos + SPRITE_BOTTOM_RIGHT_OFFSET
|
|
83
|
+
sprite:RenderLayer(0, position)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
function IsaacScriptWatcher:RenderText()
|
|
88
|
+
-- Don't draw IsaacScript text when custom consoles are open.
|
|
89
|
+
if AwaitingTextInput then
|
|
90
|
+
return
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
if frameOfLastMsg == 0 then
|
|
94
|
+
return
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
if game:IsPaused() then
|
|
98
|
+
return
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
if ModConfigMenu ~= nil then
|
|
102
|
+
if ModConfigMenu.IsVisible then
|
|
103
|
+
return
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
-- Local variables
|
|
108
|
+
local x = 60
|
|
109
|
+
local y = 90
|
|
110
|
+
local scale = 1
|
|
111
|
+
local lineHeight = font:GetLineHeight() * scale
|
|
112
|
+
|
|
113
|
+
-- The text will slowly fade out.
|
|
114
|
+
local elapsedFrames = Isaac.GetFrameCount() - frameOfLastMsg
|
|
115
|
+
local alpha
|
|
116
|
+
if elapsedFrames <= FRAMES_BEFORE_TEXT_FADE then
|
|
117
|
+
alpha = 1
|
|
118
|
+
else
|
|
119
|
+
local fadeFrames = elapsedFrames - FRAMES_BEFORE_TEXT_FADE
|
|
120
|
+
alpha = 1 - (0.02 * fadeFrames)
|
|
121
|
+
end
|
|
122
|
+
if alpha <= 0 then
|
|
123
|
+
frameOfLastMsg = 0
|
|
124
|
+
return
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
local white = KColor(1, 1, 1, alpha)
|
|
128
|
+
local red = KColor(1, 0, 0, alpha)
|
|
129
|
+
local green = KColor(0, 1, 0, alpha)
|
|
130
|
+
|
|
131
|
+
-- Go through each message.
|
|
132
|
+
for i, msg in ipairs(messageArray) do
|
|
133
|
+
local color = white
|
|
134
|
+
|
|
135
|
+
local hasSuccess = string.match(msg, "Compilation successful.")
|
|
136
|
+
if hasSuccess ~= nil then
|
|
137
|
+
color = green
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
local hasErrors = string.match(msg, "Found [0-9]+ errors.")
|
|
141
|
+
if hasErrors ~= nil then
|
|
142
|
+
color = red
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
font:DrawStringScaledUTF8(
|
|
146
|
+
msg,
|
|
147
|
+
x,
|
|
148
|
+
y + ((i - 1) * lineHeight),
|
|
149
|
+
scale,
|
|
150
|
+
scale,
|
|
151
|
+
color,
|
|
152
|
+
0,
|
|
153
|
+
true
|
|
154
|
+
)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
function IsaacScriptWatcher:LoadSaveDat()
|
|
159
|
+
-- Local variables
|
|
160
|
+
local isaacFrameCount = Isaac.GetFrameCount()
|
|
161
|
+
|
|
162
|
+
-- Read the "save.dat" file every third second, since file reads are expensive.
|
|
163
|
+
if isaacFrameCount % 20 ~= 0 then
|
|
164
|
+
return
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
-- Check to see if there a "save.dat" file for this save slot.
|
|
168
|
+
if not Isaac.HasModData(IsaacScriptWatcher) then
|
|
169
|
+
IsaacScriptWatcher:ClearSaveDat()
|
|
170
|
+
return
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
-- The server will write JSON data for us to the "save#.dat" file in the mod subdirectory.
|
|
174
|
+
if not pcall(IsaacScriptWatcher.Load) then
|
|
175
|
+
-- Sometimes loading can fail if the file is currently being being written to, so give up for
|
|
176
|
+
-- now and try again on the next interval.
|
|
177
|
+
Isaac.DebugString(
|
|
178
|
+
MOD_NAME
|
|
179
|
+
.. " - Failed to load the TypeScript Watcher \"save.dat\" on frame: "
|
|
180
|
+
.. tostring(isaacFrameCount)
|
|
181
|
+
)
|
|
182
|
+
return
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
if #saveData > 0 then
|
|
186
|
+
local saveDatContents = saveData
|
|
187
|
+
IsaacScriptWatcher:ClearSaveDat()
|
|
188
|
+
IsaacScriptWatcher:LoadSuccessful(saveDatContents)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
function IsaacScriptWatcher:LoadSuccessful(saveDatContents)
|
|
193
|
+
frameOfLastSuccessfulLoad = Isaac.GetFrameCount()
|
|
194
|
+
|
|
195
|
+
for _, entry in ipairs(saveDatContents) do
|
|
196
|
+
-- Entry is e.g. { type: "command", data: "luamod revelations" }
|
|
197
|
+
if entry.type == "command" then
|
|
198
|
+
if entry.data == "restart" then
|
|
199
|
+
-- If we restart on the first frame that a run is loading, then the game can crash.
|
|
200
|
+
restartFrame = Isaac.GetFrameCount() + 1
|
|
201
|
+
else
|
|
202
|
+
Isaac.DebugString(MOD_NAME .. " - Executing command: " .. entry.data)
|
|
203
|
+
Isaac.ExecuteCommand(entry.data)
|
|
204
|
+
end
|
|
205
|
+
elseif entry.type == "msg" then
|
|
206
|
+
Isaac.DebugString(MOD_NAME .. " - " .. entry.data)
|
|
207
|
+
pushMessageArray(entry.data)
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
function IsaacScriptWatcher:ClearSaveDat()
|
|
213
|
+
saveData = {}
|
|
214
|
+
IsaacScriptWatcher:Save()
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
function IsaacScriptWatcher:Save()
|
|
218
|
+
local saveDataJSON = json.encode(saveData)
|
|
219
|
+
IsaacScriptWatcher:SaveData(saveDataJSON)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
function IsaacScriptWatcher:Load()
|
|
223
|
+
-- Read the "save#.dat" file into a string.
|
|
224
|
+
local saveDataJSON = Isaac.LoadModData(IsaacScriptWatcher)
|
|
225
|
+
|
|
226
|
+
-- Handle the case of a 0 byte file.
|
|
227
|
+
if saveDataJSON == "" then
|
|
228
|
+
saveDataJSON = "{}"
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
-- Convert a JSON string to a Lua table.
|
|
232
|
+
saveData = json.decode(saveDataJSON)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
function IsaacScriptWatcher:CheckInput()
|
|
236
|
+
if game:IsPaused() then
|
|
237
|
+
return
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
-- Ensure that this feature does not overlap with custom consoles by checking for the
|
|
241
|
+
-- "AwaitingTextInput" global variable.
|
|
242
|
+
if AwaitingTextInput then
|
|
243
|
+
return
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
-- Manually show the log when the user presses the "I" key on the keyboard.
|
|
247
|
+
if Input.IsButtonPressed(Keyboard.KEY_I, 0) then
|
|
248
|
+
frameOfLastMsg = Isaac.GetFrameCount()
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
function IsaacScriptWatcher:CheckRestart()
|
|
253
|
+
if not RESTART_GAME_ON_RECOMPILATION then
|
|
254
|
+
return
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
if restartFrame == 0 or restartFrame < Isaac.GetFrameCount() then
|
|
258
|
+
return
|
|
259
|
+
end
|
|
260
|
+
restartFrame = 0
|
|
261
|
+
|
|
262
|
+
Isaac.DebugString(MOD_NAME .. " - Restarting the run.")
|
|
263
|
+
Isaac.ExecuteCommand("restart")
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
IsaacScriptWatcher:AddCallback(ModCallbacks.MC_POST_RENDER, IsaacScriptWatcher.PostRender)
|
|
267
|
+
|
|
268
|
+
local initMessage = "IsaacScript Watcher initialized."
|
|
269
|
+
Isaac.DebugString(initMessage)
|
|
270
|
+
pushMessageArray(initMessage)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<AnimatedActor>
|
|
2
|
+
<Info CreatedBy="Unknown" CreatedOn="2/1/2017 6:09:20 AM" Version="2" Fps="30"/>
|
|
3
|
+
<Content>
|
|
4
|
+
<Spritesheets>
|
|
5
|
+
<Spritesheet Path="logo.png" Id="0"/>
|
|
6
|
+
</Spritesheets>
|
|
7
|
+
<Layers>
|
|
8
|
+
<Layer Name="Layer 0" Id="0" SpritesheetId="0"/>
|
|
9
|
+
</Layers>
|
|
10
|
+
<Nulls/>
|
|
11
|
+
<Events/>
|
|
12
|
+
</Content>
|
|
13
|
+
<Animations DefaultAnimation="Default">
|
|
14
|
+
<Animation Name="Default" FrameNum="1" Loop="true">
|
|
15
|
+
<RootAnimation>
|
|
16
|
+
<Frame XPosition="0" YPosition="0" XScale="100" YScale="100" Delay="1" Visible="true" RedTint="255" GreenTint="255" BlueTint="255" AlphaTint="255" RedOffset="0" GreenOffset="0" BlueOffset="0" Rotation="0" Interpolated="false"/>
|
|
17
|
+
</RootAnimation>
|
|
18
|
+
<LayerAnimations>
|
|
19
|
+
<LayerAnimation LayerId="0" Visible="true">
|
|
20
|
+
<Frame XPosition="0" YPosition="0" XPivot="0" YPivot="0" XCrop="0" YCrop="0" Width="44" Height="28" XScale="66" YScale="66" Delay="1" Visible="true" RedTint="255" GreenTint="255" BlueTint="255" AlphaTint="255" RedOffset="0" GreenOffset="0" BlueOffset="0" Rotation="0" Interpolated="false"/>
|
|
21
|
+
</LayerAnimation>
|
|
22
|
+
</LayerAnimations>
|
|
23
|
+
<NullAnimations/>
|
|
24
|
+
<Triggers/>
|
|
25
|
+
</Animation>
|
|
26
|
+
</Animations>
|
|
27
|
+
</AnimatedActor>
|
|
Binary file
|