├── .classpath
├── .gitignore
├── .project
├── .settings
└── org.eclipse.jdt.core.prefs
├── README.md
├── lib
├── CodecJOrbis.jar
├── JOrbisStandalone.jar
└── gson-2.8.2.jar
├── release
├── CellPacker.jar
├── CellPacker_Modloader.jar
└── CellPacker_old_2.0.jar
├── scripts
├── dark.patch
└── time.patch
└── src
├── dev
└── lb
│ └── cellpacker
│ ├── CellPackerMain.java
│ ├── Logger.java
│ ├── NamedRange.java
│ ├── TextAreaPrintStream.java
│ ├── Utils.java
│ ├── annotation
│ ├── Async.java
│ ├── Calculated.java
│ ├── Shortcut.java
│ └── Unmodifiable.java
│ ├── controls
│ ├── CheckBoxList.java
│ ├── JAudioPlayer.java
│ ├── JDraggableScrollPane.java
│ ├── JHistoryTextField.java
│ ├── JImageViewer.java
│ ├── JSpriteViewer.java
│ ├── LaunchWindow.java
│ ├── MainWindow.java
│ ├── SpriteSavingList.java
│ └── TutorialWindow.java
│ └── structure
│ ├── ByteData.java
│ ├── NamedObject.java
│ ├── ResourceCategory.java
│ ├── ResourceContainer.java
│ ├── ResourceFile.java
│ ├── ResourceViewManager.java
│ ├── Script.java
│ ├── SearchableResourceViewManager.java
│ ├── ViewCategory.java
│ ├── cdb
│ ├── CDBFile.java
│ ├── Column.java
│ ├── Line.java
│ ├── ScriptReader.java
│ ├── Sheet.java
│ └── SheetProps.java
│ ├── resource
│ ├── AtlasResource.java
│ ├── CompoundAtlasResource.java
│ ├── FontResource.java
│ ├── ImageResource.java
│ ├── JsonResource.java
│ ├── Resource.java
│ └── SoundResource.java
│ └── view
│ ├── AtlasImageResourceView.java
│ ├── CastleDBResourceView.java
│ ├── FontResourceView.java
│ ├── JsonResourceView.java
│ ├── ResourceView.java
│ ├── SingleResourceView.java
│ └── StaticResourceView.java
└── resources
└── ico.png
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | CellPacker
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.8
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.source=1.8
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CellPacker [Outdated]
2 |
3 | **Dead Cells now has its own
4 | (basic) modding tools.** This project is no longer required and might not support newer versions of the game.
5 |
6 | CellPacker can still be used as a resource viewer and editor (unless the res.pak format changes in the future), but can **not** be
7 | used to create mods compatible with the Steam workshop
8 |
9 | ## [Old description below]
10 |
11 | A modding utility for Dead Cells
12 |
13 | Version 2.1 of CellPacker: Information and Help
14 | Please read this file before using the program.
15 | The compiled file can be found [here](https://github.com/ReBuilders101/CellPacker/raw/master/release/CellPacker.jar).
16 |
17 | --------------------------------------------------------------------------------------------------------
18 | CellPacker is an application to view and modify the resources used by the game Dead Cells.
19 | **NOTE:** The format of the Dead Cells resource file can change at any time and there is no official
20 | documentation. This program was designed to be used with the Baguette Update, but will most
21 | likely also work on newer and older versions.
22 |
23 | --------------------------------------------------------------------------------------------------------
24 | ### Features:
25 |
26 | 1. View all images/textures of the game that are stored in the resource file
27 | 2. Play all sounds stored in the resource files
28 | 3. Group connected resources into views, so they are easier to find
29 | 4. Export all resources as files (PNG for images, OGG for sounds)
30 | 5. Search for resources
31 | 6. Replace reources with custom ones. This way you can create your own textures or sounds for the game
32 | 7. Re-pack the modified file so it can be used by Dead Cells
33 | 8. ~~A launcher that lets you run scripts to modify the resources, so you can choose if you want to play with modifications without opening the editor~~
34 | 9. Editing of the game data, either with a text editor or with the external program [CastleDB](http://castledb.org/) (recommended)
35 |
36 |
37 | --------------------------------------------------------------------------------------------------------
38 | ### How to use:
39 | #### Download
40 | [CellPacker Download](https://github.com/ReBuilders101/CellPacker/raw/master/release/CellPacker.jar)
41 | ##### Editor
42 | 1. CellPacker.jar can be run from any folder. Double-click to execute (Java 8 or newer must be installed)
43 | 2. Use File>Open to open the res.pak file in your Dead Cells folder (usually found at /steamapps/common/Dead Cells/)
44 | 3. On the right, a tree with all found resources will appear. Click on an item to see the resource.
45 | 4. To replace a resource or to export it to a file, select Edit>Resource Options and choose your option.
46 | **IMPORTANT:** When replacing images, make sure the replacement has the same size (pixles, not bytes) as the original.
47 | 5. You can always restore a modified resource to its original state with the Resource Options menu.
48 | 6. To create a version containing your changes that is useable by Dead Cells, simply use File>Save and overwrite the
49 | existing res.pak file. Mare sure to back up the original file before.
50 |
51 | ##### ~~Scripting~~
52 | The scripting feature was never fully implemented and was made obsolete when modding through the Steam Workshop was introduced
53 |
54 | ##### Uninstall
55 | CellPacker does not create any permanent files. Simply delete the CellPacker.jar file to delete the program from your computer.
56 |
57 | --------------------------------------------------------------------------------------------------------
58 | ### Compiled files and code:
59 | ##### Compiled files
60 | Use the CellPacker.jar in the release folder.
61 | ##### If you want to compile the code:
62 | This repository contains a full eclipse project, you can just clone and import it. It will probably also work with any other IDE.
63 | All jar files in the `lib` folder are dependencies.
64 |
65 | --------------------------------------------------------------------------------------------------------
66 | ### License:
67 | Basic:
68 | * Do whatever you want.
69 |
70 | But:
71 | * Please don't claim that you made this. It's not nice.
72 | * Feel free to take any code from this project and use it for your own project.
73 |
74 | Also:
75 | * If Dead Cells breaks, it is not my fault.
76 |
77 | ##### Third Party Licenses and Credits:
78 | This program uses the following third party librarys:
79 | - CodecJOrbis by Paul Lamb (http://paulscode.com), because Java does not support the OGG sound format.
80 | - Gson (under the Apache License 2.0, can be found at http://www.apache.org/licenses/LICENSE-2.0) to parse JSON.
81 |
--------------------------------------------------------------------------------
/lib/CodecJOrbis.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReBuilders101/CellPacker/27babca69bdae7b8d9ad7ccc2c1b864853b30632/lib/CodecJOrbis.jar
--------------------------------------------------------------------------------
/lib/JOrbisStandalone.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReBuilders101/CellPacker/27babca69bdae7b8d9ad7ccc2c1b864853b30632/lib/JOrbisStandalone.jar
--------------------------------------------------------------------------------
/lib/gson-2.8.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReBuilders101/CellPacker/27babca69bdae7b8d9ad7ccc2c1b864853b30632/lib/gson-2.8.2.jar
--------------------------------------------------------------------------------
/release/CellPacker.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReBuilders101/CellPacker/27babca69bdae7b8d9ad7ccc2c1b864853b30632/release/CellPacker.jar
--------------------------------------------------------------------------------
/release/CellPacker_Modloader.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReBuilders101/CellPacker/27babca69bdae7b8d9ad7ccc2c1b864853b30632/release/CellPacker_Modloader.jar
--------------------------------------------------------------------------------
/release/CellPacker_old_2.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReBuilders101/CellPacker/27babca69bdae7b8d9ad7ccc2c1b864853b30632/release/CellPacker_old_2.0.jar
--------------------------------------------------------------------------------
/scripts/dark.patch:
--------------------------------------------------------------------------------
1 | {
2 | "add": {
3 | "sheets":[
4 | {
5 | "CPWHERE": {
6 | "id": "name",
7 | "value": "level"
8 | },
9 | "lines": [
10 | {
11 | "CPWHERE": {
12 | "id": "id",
13 | "value": "PrisonStart"
14 | },
15 | "flags": 64
16 | },
17 | {
18 | "CPWHERE": {
19 | "id": "id",
20 | "value": "PrisonCourtyard"
21 | },
22 | "flags": 65
23 | },
24 | {
25 | "CPWHERE": {
26 | "id": "id",
27 | "value": "PrisonDepths"
28 | },
29 | "flags": 64
30 | },
31 | {
32 | "CPWHERE": {
33 | "id": "id",
34 | "value": "SewerShort"
35 | },
36 | "flags": 72
37 | },
38 | {
39 | "CPWHERE": {
40 | "id": "id",
41 | "value": "PrisonStart"
42 | },
43 | "flags": 64
44 | },
45 | {
46 | "CPWHERE": {
47 | "id": "id",
48 | "value": "PrisonRoof"
49 | },
50 | "flags": 65
51 | },
52 | {
53 | "CPWHERE": {
54 | "id": "id",
55 | "value": "SewerDepths"
56 | },
57 | "flags": 72
58 | },
59 | {
60 | "CPWHERE": {
61 | "id": "id",
62 | "value": "Ossuary"
63 | },
64 | "flags": 64
65 | },
66 | {
67 | "CPWHERE": {
68 | "id": "id",
69 | "value": "StiltVillage"
70 | },
71 | "flags": 325
72 | },
73 | {
74 | "CPWHERE": {
75 | "id": "id",
76 | "value": "AncientTemple"
77 | },
78 | "flags": 64
79 | },
80 | {
81 | "CPWHERE": {
82 | "id": "id",
83 | "value": "Cemetery"
84 | },
85 | "flags": 65
86 | },
87 | {
88 | "CPWHERE": {
89 | "id": "id",
90 | "value": "ClockTower"
91 | },
92 | "flags": 192
93 | }
94 | ]
95 | }
96 | ,
97 | {
98 | "CPWHERE": {
99 | "id": "name",
100 | "value": "room"
101 | },
102 | "lines": [
103 | {
104 | "CPWHERE": {
105 | "id": "id",
106 | "value": "PrisonFlaskRoom"
107 | },
108 | "markers": [
109 | {
110 | "x": 28,
111 | "y": 30,
112 | "marker": "DarknessRemover",
113 | "width": 1,
114 | "height": 1,
115 | "customId": "-7"
116 | },
117 | {
118 | "x": 93,
119 | "y": 28,
120 | "marker": "DarknessRemover",
121 | "width": 1,
122 | "height": 1,
123 | "customId": "-7"
124 | },
125 | {
126 | "x": 83,
127 | "y": 26,
128 | "marker": "DarknessRemover",
129 | "width": 1,
130 | "height": 1,
131 | "customId": "-7"
132 | },
133 | {
134 | "x": 51,
135 | "y": 26,
136 | "marker": "DarknessRemover",
137 | "width": 1,
138 | "height": 1,
139 | "customId": "-7"
140 | }
141 | ]
142 | },
143 | {
144 | "CPWHERE": {
145 | "id": "id",
146 | "value": "Exit_LR"
147 | },
148 | "markers": [
149 | {
150 | "x": 3,
151 | "y": 7,
152 | "marker": "DarknessRemover",
153 | "width": 1,
154 | "height": 1,
155 | "customId": "-7"
156 | },
157 | {
158 | "x": 11,
159 | "y": 7,
160 | "marker": "DarknessRemover",
161 | "width": 1,
162 | "height": 1,
163 | "customId": "-7"
164 | }
165 | ]
166 | },
167 | {
168 | "CPWHERE": {
169 | "id": "id",
170 | "value": "Exit_LDR"
171 | },
172 | "markers": [
173 | {
174 | "x": 6,
175 | "y": 6,
176 | "marker": "DarknessRemover",
177 | "width": 1,
178 | "height": 1,
179 | "customId": "-7"
180 | },
181 | {
182 | "x": 16,
183 | "y": 6,
184 | "marker": "DarknessRemover",
185 | "width": 1,
186 | "height": 1,
187 | "customId": "-7"
188 | }
189 | ]
190 | },
191 | {
192 | "CPWHERE": {
193 | "id": "id",
194 | "value": "Exit_UL"
195 | },
196 | "markers": [
197 | {
198 | "x": 7,
199 | "y": 5,
200 | "marker": "DarknessRemover",
201 | "width": 1,
202 | "height": 1,
203 | "customId": "-7"
204 | }
205 | ]
206 | },
207 | {
208 | "CPWHERE": {
209 | "id": "id",
210 | "value": "Exit_DL"
211 | },
212 | "markers": [
213 | {
214 | "x": 9,
215 | "y": 11,
216 | "marker": "DarknessRemover",
217 | "width": 1,
218 | "height": 1,
219 | "customId": "-7"
220 | }
221 | ]
222 | },
223 | {
224 | "CPWHERE": {
225 | "id": "id",
226 | "value": "BasicEntrance_R"
227 | },
228 | "markers": [
229 | {
230 | "x": 22,
231 | "y": 8,
232 | "marker": "DarknessRemover",
233 | "width": 1,
234 | "height": 1,
235 | "customId": "-7"
236 | }
237 | ]
238 | },
239 | {
240 | "CPWHERE": {
241 | "id": "id",
242 | "value": "BasicEntrance_D"
243 | },
244 | "markers": [
245 | {
246 | "x": 14,
247 | "y": 12,
248 | "marker": "DarknessRemover",
249 | "width": 1,
250 | "height": 1,
251 | "customId": "-7"
252 | }
253 | ]
254 | },
255 | {
256 | "CPWHERE": {
257 | "id": "id",
258 | "value": "BasicEntrance_U"
259 | },
260 | "markers": [
261 | {
262 | "x": 17,
263 | "y": 7,
264 | "marker": "DarknessRemover",
265 | "width": 1,
266 | "height": 1,
267 | "customId": "-7"
268 | }
269 | ]
270 | },
271 | {
272 | "CPWHERE": {
273 | "id": "id",
274 | "value": "OutsideEntrance"
275 | },
276 | "markers": [
277 | {
278 | "x": 22,
279 | "y": 14,
280 | "marker": "DarknessRemover",
281 | "width": 1,
282 | "height": 1,
283 | "customId": "-7"
284 | }
285 | ]
286 | },
287 | {
288 | "CPWHERE": {
289 | "id": "id",
290 | "value": "PrisonStartExit"
291 | },
292 | "markers": [
293 | {
294 | "x": 26,
295 | "y": 5,
296 | "marker": "DarknessRemover",
297 | "width": 1,
298 | "height": 1,
299 | "customId": "-7"
300 | }
301 | ]
302 | },
303 | {
304 | "CPWHERE": {
305 | "id": "id",
306 | "value": "PrisonMonsterDoor"
307 | },
308 | "markers": [
309 | {
310 | "x": 2,
311 | "y": 10,
312 | "marker": "DarknessRemover",
313 | "width": 1,
314 | "height": 1,
315 | "customId": "5"
316 | },
317 | {
318 | "x": 10,
319 | "y": 10,
320 | "marker": "DarknessRemover",
321 | "width": 1,
322 | "height": 1,
323 | "customId": "5"
324 | }
325 | ]
326 | },
327 | {
328 | "CPWHERE": {
329 | "id": "id",
330 | "value": "PrisonDepthsEntrance"
331 | },
332 | "markers": [
333 | {
334 | "x": 22,
335 | "y": 16,
336 | "marker": "DarknessRemover",
337 | "width": 1,
338 | "height": 1,
339 | "customId": "-7"
340 | }
341 | ]
342 | },
343 | {
344 | "CPWHERE": {
345 | "id": "id",
346 | "value": "PrisonHubEntrance"
347 | },
348 | "markers": [
349 | {
350 | "x": 19,
351 | "y": 17,
352 | "marker": "DarknessRemover",
353 | "width": 1,
354 | "height": 1,
355 | "customId": "-7"
356 | }
357 | ]
358 | },
359 | {
360 | "CPWHERE": {
361 | "id": "id",
362 | "value": "RoofEntrance"
363 | },
364 | "markers": [
365 | {
366 | "x": 23,
367 | "y": 8,
368 | "marker": "DarknessRemover",
369 | "width": 1,
370 | "height": 1,
371 | "customId": "5"
372 | },
373 | {
374 | "x": 18,
375 | "y": 28,
376 | "marker": "DarknessRemover",
377 | "width": 1,
378 | "height": 1,
379 | "customId": "-7"
380 | }
381 | ]
382 | },
383 | {
384 | "CPWHERE": {
385 | "id": "id",
386 | "value": "RoofEndSubRoom"
387 | },
388 | "markers": [
389 | {
390 | "x": 9,
391 | "y": 18,
392 | "marker": "DarknessRemover",
393 | "width": 1,
394 | "height": 1,
395 | "customId": "-7"
396 | }
397 | ]
398 | },
399 | {
400 | "CPWHERE": {
401 | "id": "id",
402 | "value": "RoofEndNothing"
403 | },
404 | "markers": [
405 | {
406 | "x": 9,
407 | "y": 18,
408 | "marker": "DarknessRemover",
409 | "width": 1,
410 | "height": 1,
411 | "customId": "-7"
412 | }
413 | ]
414 | },
415 | {
416 | "CPWHERE": {
417 | "id": "id",
418 | "value": "RoofEndBridge"
419 | },
420 | "markers": [
421 | {
422 | "x": 9,
423 | "y": 15,
424 | "marker": "DarknessRemover",
425 | "width": 1,
426 | "height": 1,
427 | "customId": "5"
428 | },
429 | {
430 | "x": 39,
431 | "y": 16,
432 | "marker": "DarknessRemover",
433 | "width": 1,
434 | "height": 1,
435 | "customId": "-7"
436 | }
437 | ]
438 | },
439 | {
440 | "CPWHERE": {
441 | "id": "id",
442 | "value": "RoofEndExit"
443 | },
444 | "markers": [
445 | {
446 | "x": 13,
447 | "y": 26,
448 | "marker": "DarknessRemover",
449 | "width": 1,
450 | "height": 1,
451 | "customId": "5"
452 | },
453 | {
454 | "x": 23,
455 | "y": 108,
456 | "marker": "DarknessRemover",
457 | "width": 1,
458 | "height": 1,
459 | "customId": "-7"
460 | }
461 | ]
462 | },
463 | {
464 | "CPWHERE": {
465 | "id": "id",
466 | "value": "RoofInnerExit"
467 | },
468 | "markers": [
469 | {
470 | "x": 14,
471 | "y": 5,
472 | "marker": "DarknessRemover",
473 | "width": 1,
474 | "height": 1,
475 | "customId": "-7"
476 | }
477 | ]
478 | },
479 | {
480 | "CPWHERE": {
481 | "id": "id",
482 | "value": "SewerShortEntrance"
483 | },
484 | "markers": [
485 | {
486 | "x": 13,
487 | "y": 5,
488 | "marker": "DarknessRemover",
489 | "width": 1,
490 | "height": 1,
491 | "customId": "5"
492 | },
493 | {
494 | "x": 25,
495 | "y": 12,
496 | "marker": "DarknessRemover",
497 | "width": 1,
498 | "height": 1,
499 | "customId": "-7"
500 | }
501 | ]
502 | },
503 | {
504 | "CPWHERE": {
505 | "id": "id",
506 | "value": "SewerDepthsEntrance"
507 | },
508 | "markers": [
509 | {
510 | "x": 24,
511 | "y": 9,
512 | "marker": "DarknessRemover",
513 | "width": 1,
514 | "height": 1,
515 | "customId": "5"
516 | },
517 | {
518 | "x": 32,
519 | "y": 23,
520 | "marker": "DarknessRemover",
521 | "width": 1,
522 | "height": 1,
523 | "customId": "-7"
524 | }
525 | ]
526 | },
527 | {
528 | "CPWHERE": {
529 | "id": "id",
530 | "value": "SewerCreature"
531 | },
532 | "markers": [
533 | {
534 | "x": 12,
535 | "y": 6,
536 | "marker": "DarknessRemover",
537 | "width": 1,
538 | "height": 1,
539 | "customId": "5"
540 | },
541 | {
542 | "x": 31,
543 | "y": 6,
544 | "marker": "DarknessRemover",
545 | "width": 1,
546 | "height": 1,
547 | "customId": "-7"
548 | }
549 | ]
550 | },
551 | {
552 | "CPWHERE": {
553 | "id": "id",
554 | "value": "OssEntrance"
555 | },
556 | "markers": [
557 | {
558 | "x": 18,
559 | "y": 24,
560 | "marker": "DarknessRemover",
561 | "width": 1,
562 | "height": 1,
563 | "customId": "5"
564 | },
565 | {
566 | "x": 45,
567 | "y": 28,
568 | "marker": "DarknessRemover",
569 | "width": 1,
570 | "height": 1,
571 | "customId": "-7"
572 | }
573 | ]
574 | },
575 | {
576 | "CPWHERE": {
577 | "id": "id",
578 | "value": "SVEntrance"
579 | },
580 | "markers": [
581 | {
582 | "x": 8,
583 | "y": 20,
584 | "marker": "DarknessRemover",
585 | "width": 1,
586 | "height": 1,
587 | "customId": "-7"
588 | }
589 | ]
590 | },
591 | {
592 | "CPWHERE": {
593 | "id": "id",
594 | "value": "SVEnd"
595 | },
596 | "markers": [
597 | {
598 | "x": 28,
599 | "y": 26,
600 | "marker": "DarknessRemover",
601 | "width": 1,
602 | "height": 1,
603 | "customId": "-7"
604 | },
605 | {
606 | "x": 12,
607 | "y": 80,
608 | "marker": "DarknessRemover",
609 | "width": 1,
610 | "height": 1,
611 | "customId": "-7"
612 | },
613 | {
614 | "x": 10,
615 | "y": 90,
616 | "marker": "DarknessRemover",
617 | "width": 1,
618 | "height": 1,
619 | "customId": "-7"
620 | },
621 | {
622 | "x": 31,
623 | "y": 90,
624 | "marker": "DarknessRemover",
625 | "width": 1,
626 | "height": 1,
627 | "customId": "-7"
628 | },
629 | {
630 | "x": 59,
631 | "y": 90,
632 | "marker": "DarknessRemover",
633 | "width": 1,
634 | "height": 1,
635 | "customId": "-7"
636 | }
637 | ]
638 | },
639 | {
640 | "CPWHERE": {
641 | "id": "id",
642 | "value": "SVInteriorExit"
643 | },
644 | "markers": [
645 | {
646 | "x": 22,
647 | "y": 40,
648 | "marker": "DarknessRemover",
649 | "width": 1,
650 | "height": 1,
651 | "customId": "-7"
652 | }
653 | ]
654 | },
655 | {
656 | "CPWHERE": {
657 | "id": "id",
658 | "value": "SVMidGate"
659 | },
660 | "markers": [
661 | {
662 | "x": 11,
663 | "y": 52,
664 | "marker": "DarknessRemover",
665 | "width": 1,
666 | "height": 1,
667 | "customId": "5"
668 | },
669 | {
670 | "x": 8,
671 | "y": 87,
672 | "marker": "DarknessRemover",
673 | "width": 1,
674 | "height": 1,
675 | "customId": "-7"
676 | },
677 | {
678 | "x": 14,
679 | "y": 87,
680 | "marker": "DarknessRemover",
681 | "width": 1,
682 | "height": 1,
683 | "customId": "-7"
684 | }
685 | ]
686 | },
687 | {
688 | "CPWHERE": {
689 | "id": "id",
690 | "value": "CEntrance"
691 | },
692 | "markers": [
693 | {
694 | "x": 7,
695 | "y": 27,
696 | "marker": "DarknessRemover",
697 | "width": 1,
698 | "height": 1,
699 | "customId": "5"
700 | },
701 | {
702 | "x": 14,
703 | "y": 96,
704 | "marker": "DarknessRemover",
705 | "width": 1,
706 | "height": 1,
707 | "customId": "-7"
708 | },
709 | {
710 | "x": 30,
711 | "y": 96,
712 | "marker": "DarknessRemover",
713 | "width": 1,
714 | "height": 1,
715 | "customId": "-7"
716 | }
717 | ]
718 | },
719 | {
720 | "CPWHERE": {
721 | "id": "id",
722 | "value": "CEndExit"
723 | },
724 | "markers": [
725 | {
726 | "x": 22,
727 | "y": 27,
728 | "marker": "DarknessRemover",
729 | "width": 1,
730 | "height": 1,
731 | "customId": "5"
732 | },
733 | {
734 | "x": 8,
735 | "y": 83,
736 | "marker": "DarknessRemover",
737 | "width": 1,
738 | "height": 1,
739 | "customId": "-7"
740 | },
741 | {
742 | "x": 33,
743 | "y": 83,
744 | "marker": "DarknessRemover",
745 | "width": 1,
746 | "height": 1,
747 | "customId": "-7"
748 | }
749 | ]
750 | },
751 | {
752 | "CPWHERE": {
753 | "id": "id",
754 | "value": "CLadderGateDone"
755 | },
756 | "markers": [
757 | {
758 | "x": 15,
759 | "y": 15,
760 | "marker": "DarknessRemover",
761 | "width": 1,
762 | "height": 1,
763 | "customId": "-7"
764 | }
765 | ]
766 | },
767 | {
768 | "CPWHERE": {
769 | "id": "id",
770 | "value": "CemEntrance"
771 | },
772 | "markers": [
773 | {
774 | "x": 26,
775 | "y": 48,
776 | "marker": "DarknessRemover",
777 | "width": 1,
778 | "height": 1,
779 | "customId": "-7"
780 | }
781 | ]
782 | },
783 | {
784 | "CPWHERE": {
785 | "id": "id",
786 | "value": "CemEnd"
787 | },
788 | "markers": [
789 | {
790 | "x": 13,
791 | "y": 71,
792 | "marker": "DarknessRemover",
793 | "width": 1,
794 | "height": 1,
795 | "customId": "-7"
796 | }
797 | ]
798 | },
799 | {
800 | "CPWHERE": {
801 | "id": "id",
802 | "value": "CemBigCrypt"
803 | },
804 | "markers": [
805 | {
806 | "x": 7,
807 | "y": 22,
808 | "marker": "DarknessRemover",
809 | "width": 1,
810 | "height": 1,
811 | "customId": "5"
812 | },
813 | {
814 | "x": 48,
815 | "y": 22,
816 | "marker": "DarknessRemover",
817 | "width": 1,
818 | "height": 1,
819 | "customId": "-7"
820 | },
821 | {
822 | "x": 18,
823 | "y": 38,
824 | "marker": "DarknessRemover",
825 | "width": 1,
826 | "height": 1,
827 | "customId": "-7"
828 | }
829 | ]
830 | },
831 | {
832 | "CPWHERE": {
833 | "id": "id",
834 | "value": "ClockTowerEntrance"
835 | },
836 | "markers": [
837 | {
838 | "x": 49,
839 | "y": 13,
840 | "marker": "DarknessRemover",
841 | "width": 1,
842 | "height": 1,
843 | "customId": "5"
844 | },
845 | {
846 | "x": 33,
847 | "y": 31,
848 | "marker": "DarknessRemover",
849 | "width": 1,
850 | "height": 1,
851 | "customId": "-7"
852 | },
853 | {
854 | "x": 53,
855 | "y": 31,
856 | "marker": "DarknessRemover",
857 | "width": 1,
858 | "height": 1,
859 | "customId": "-7"
860 | }
861 | ]
862 | },
863 | {
864 | "CPWHERE": {
865 | "id": "id",
866 | "value": "ClockTowerExit"
867 | },
868 | "markers": [
869 | {
870 | "x": 4,
871 | "y": 8,
872 | "marker": "DarknessRemover",
873 | "width": 1,
874 | "height": 1,
875 | "customId": "-7"
876 | }
877 | ]
878 | },
879 | {
880 | "CPWHERE": {
881 | "id": "id",
882 | "value": "AncientEntrance"
883 | },
884 | "markers": [
885 | {
886 | "x": 20,
887 | "y": 14,
888 | "marker": "DarknessRemover",
889 | "width": 1,
890 | "height": 1,
891 | "customId": "-7"
892 | }
893 | ]
894 | }
895 | ]
896 | }
897 | ]
898 | }
899 | }
--------------------------------------------------------------------------------
/scripts/time.patch:
--------------------------------------------------------------------------------
1 | {
2 | "add": {
3 | "sheets":[
4 | {
5 | "CPWHERE": {
6 | "id": "name", "value": "room"
7 | }
8 | ,
9 | "lines": [
10 | {
11 | "CPWHERE": {
12 | "id": "id",
13 | "value": "PrisonFlaskRoom"
14 | }
15 | ,
16 | "markers": [
17 | {
18 | "x": 85,
19 | "y": 26,
20 | "marker": "FixedLoot",
21 | "width": 1,
22 | "height": 1,
23 | "item": "TimeDistorsion"
24 | },
25 | {
26 | "x": 83,
27 | "y": 26,
28 | "marker": "FixedBlueprint",
29 | "width": 1,
30 | "height": 1,
31 | "item": "TimeDistorsion"
32 | }
33 | ]
34 | }
35 | ]
36 | },
37 | {
38 | "CPWHERE": {
39 | "id": "name", "value": "item"
40 | }
41 | ,
42 | "lines": [
43 | {
44 | "CPWHERE": {
45 | "id": "id", "value": "TimeDistorsion"
46 | }
47 | ,
48 | "droppable": true,
49 | "hasLevels": true,
50 | "cellCost": 1
51 | }
52 | ]
53 | }
54 | ]
55 | }
56 | }
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/CellPackerMain.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker;
2 |
3 | import java.io.File;
4 |
5 | import javax.swing.ImageIcon;
6 | import javax.swing.UIManager;
7 | import javax.swing.UnsupportedLookAndFeelException;
8 |
9 | import dev.lb.cellpacker.controls.LaunchWindow;
10 | import dev.lb.cellpacker.controls.MainWindow;
11 |
12 | public class CellPackerMain {
13 |
14 | public static final boolean MODLOADER = false;
15 |
16 | public static boolean ASK_RESOURCE_RESTORE = true;
17 | public static File CHOOSE_ROOT_FILE = new File(".");
18 |
19 | public static MainWindow mainFrame;
20 |
21 | public static void main(String[] args) {
22 | try {
23 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
24 | } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
25 | | UnsupportedLookAndFeelException e1) {
26 | Logger.printWarning("CellPackerMain.main()", "Could not set L&F for this platform");
27 | }
28 |
29 | if(MODLOADER){
30 | LaunchWindow lw = new LaunchWindow(false);
31 | lw.setVisible(true);
32 | lw.setIconImage(new ImageIcon(CellPackerMain.class.getResource("/resources/ico.png")).getImage());
33 | }else{
34 | mainFrame = new MainWindow();
35 | mainFrame.setVisible(true);
36 | }
37 | }
38 |
39 |
40 | @SuppressWarnings("unused")
41 | private static String concat(String[] array){
42 | if(array == null) return null;
43 | if(array.length == 0) return null;
44 | String concat = "";
45 | for(String s : array){
46 | concat = concat + s + " ";
47 | }
48 | return concat;
49 | }
50 |
51 | public static MainWindow getMainFrame(){
52 | return mainFrame;
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/Logger.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker;
2 |
3 | public final class Logger {
4 | private Logger(){}
5 |
6 | public static void throwFatal(Throwable ex, int exitCode){
7 | System.err.println("[ErrorHandler]: A fatal error has occurred:");
8 | ex.printStackTrace();
9 | System.exit(exitCode);
10 | }
11 |
12 | public static void throwFatal(Throwable ex){
13 | throwFatal(ex, 1);
14 | }
15 |
16 | public static void printWarning(String trace, String warning){
17 | System.out.println("[WARNING|" + trace + "]: " + warning);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/NamedRange.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker;
2 |
3 | public class NamedRange{
4 |
5 | private String key;
6 | private int start;
7 | private int end;
8 |
9 | public NamedRange(String name, int start) {
10 | this.key = name;
11 | this.start = start;
12 | }
13 |
14 | public String getName() {
15 | return key;
16 | }
17 |
18 | public int getStart() {
19 | return start;
20 | }
21 |
22 | public int getEnd(){
23 | return end;
24 | }
25 |
26 | public int getSize(){
27 | return end - start;
28 | }
29 |
30 | public void setEnd(int value) {
31 | end = value;
32 | }
33 |
34 | @Override
35 | public String toString() {
36 | return "NamedRange [name=" + key + ", start=" + start + ", end=" + end + "]";
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/TextAreaPrintStream.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.PrintStream;
5 |
6 | import javax.swing.JTextArea;
7 |
8 | public class TextAreaPrintStream extends PrintStream{
9 |
10 | private JTextArea textArea;
11 |
12 | public TextAreaPrintStream(JTextArea area){
13 | super(new ByteArrayOutputStream(), true);
14 | textArea = area;
15 |
16 | }
17 |
18 | @Override
19 | public void flush() {
20 | super.flush();
21 | textArea.setText(new String(((ByteArrayOutputStream) out).toByteArray()));
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/Utils.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker;
2 |
3 | import java.awt.BorderLayout;
4 | import java.awt.Component;
5 | import java.awt.Container;
6 | import java.awt.Desktop;
7 | import java.awt.Dimension;
8 | import java.awt.FlowLayout;
9 | import java.awt.LayoutManager;
10 | import java.io.ByteArrayOutputStream;
11 | import java.io.IOException;
12 | import java.io.Reader;
13 | import java.io.StringReader;
14 | import java.net.URI;
15 | import java.net.URISyntaxException;
16 | import java.util.function.Consumer;
17 | import java.util.function.Predicate;
18 | import java.util.function.Supplier;
19 |
20 | import javax.swing.BorderFactory;
21 | import javax.swing.JComponent;
22 | import javax.swing.JOptionPane;
23 | import javax.swing.JPanel;
24 | import javax.swing.JProgressBar;
25 | import javax.swing.JTextArea;
26 |
27 | import com.google.gson.JsonArray;
28 | import com.google.gson.JsonElement;
29 | import com.google.gson.JsonObject;
30 | import com.google.gson.stream.JsonReader;
31 | import com.google.gson.stream.JsonToken;
32 | import com.google.gson.stream.MalformedJsonException;
33 |
34 |
35 | public final class Utils {
36 | private Utils(){}
37 |
38 | public static T setWidth(T control, int width){
39 | control.setPreferredSize(new Dimension(width, control.getPreferredSize().height));
40 | return control;
41 | }
42 |
43 | public static T setMaxWidth(T control){
44 | control.setMaximumSize(new Dimension(Integer.MAX_VALUE, control.getMaximumSize().height));
45 | return control;
46 | }
47 |
48 | public static T call(T object, Consumer action){
49 | action.accept(object);
50 | return object;
51 | }
52 |
53 | public static T setHeight(T control, int height){
54 | control.setPreferredSize(new Dimension(control.getPreferredSize().width, height));
55 | return control;
56 | }
57 |
58 | public static T setPrefSize(T control, int width, int height){
59 | control.setPreferredSize(new Dimension(width, height));
60 | return control;
61 | }
62 |
63 | public static JPanel createGroupBox(String title){
64 | JPanel pan = new JPanel();
65 | pan.setBorder(BorderFactory.createTitledBorder(title));
66 | return pan;
67 | }
68 |
69 | public static JPanel createGroupBox(String title, LayoutManager layout){
70 | JPanel pan = new JPanel(layout);
71 | pan.setBorder(BorderFactory.createTitledBorder(title));
72 | return pan;
73 | }
74 |
75 | public static T addAll(T container, Component...components){
76 | for(Component c : components){
77 | container.add(c);
78 | }
79 | return container;
80 | }
81 |
82 | public static JTextArea getTextDisplay(String text){
83 | JTextArea txt = new JTextArea(text);
84 | txt.setEditable(false);
85 | return txt;
86 | }
87 |
88 | public static JProgressBar getWaitingBar(int width){
89 | JProgressBar pro = new JProgressBar();
90 | pro.setIndeterminate(true);
91 | return setWidth(pro, width);
92 | }
93 |
94 | public static Container asyncFill(Supplier content, int waitBarWidth){
95 | JPanel con = new JPanel();
96 | JProgressBar wait = getWaitingBar(waitBarWidth);
97 | con.add(wait);
98 | new Thread(() -> {
99 | Component com = content.get();
100 | con.remove(wait);
101 | con.setLayout(new BorderLayout());
102 | con.add(com);
103 | con.revalidate();
104 | }).start();
105 | return con;
106 | }
107 |
108 | public static Container asyncFill(Supplier content, int waitBarWidth, Object constraints){
109 | JPanel con = new JPanel();
110 | JProgressBar wait = getWaitingBar(waitBarWidth);
111 | con.add(wait, constraints);
112 | new Thread(() -> {
113 | Component com = content.get();
114 | con.remove(wait);
115 | con.setLayout(new BorderLayout());
116 | con.add(com, constraints);
117 | con.revalidate();
118 | }).start();
119 | return con;
120 | }
121 |
122 | public static JPanel pack(Component...components){
123 | JPanel container = new JPanel(new FlowLayout());
124 | for(Component c : components){
125 | container.add(c);
126 | }
127 | return container;
128 | }
129 |
130 |
131 | //Validation methods from SO
132 | public static boolean isJsonValid(final String json) {
133 | return isJsonValid(new StringReader(json));
134 | }
135 |
136 | private static boolean isJsonValid(final Reader reader) {
137 | return isJsonValid(new JsonReader(reader));
138 | }
139 |
140 | private static boolean isJsonValid(final JsonReader jsonReader) {
141 | try {
142 | JsonToken token;
143 | loop:
144 | while ( (token = jsonReader.peek()) != JsonToken.END_DOCUMENT && token != null ) {
145 | switch ( token ) {
146 | case BEGIN_ARRAY:
147 | jsonReader.beginArray();
148 | break;
149 | case END_ARRAY:
150 | jsonReader.endArray();
151 | break;
152 | case BEGIN_OBJECT:
153 | jsonReader.beginObject();
154 | break;
155 | case END_OBJECT:
156 | jsonReader.endObject();
157 | break;
158 | case NAME:
159 | jsonReader.nextName();
160 | break;
161 | case STRING:
162 | case NUMBER:
163 | case BOOLEAN:
164 | case NULL:
165 | jsonReader.skipValue();
166 | break;
167 | case END_DOCUMENT:
168 | break loop;
169 | default:
170 | throw new AssertionError(token);
171 | }
172 | }
173 | return true;
174 | } catch ( final MalformedJsonException ignored ) {
175 | return false;
176 | } catch (IOException | AssertionError e) {
177 | e.printStackTrace();
178 | return false;
179 | }
180 | }
181 |
182 | public static void showAboutDialog(String text, String title, String url){
183 | int result = JOptionPane.showOptionDialog(CellPackerMain.getMainFrame(), text, title, JOptionPane.DEFAULT_OPTION,
184 | JOptionPane.INFORMATION_MESSAGE, null, new String[]{"Go to website", "Close"}, 0);
185 | if(result == 1) return;
186 | try {
187 | Desktop.getDesktop().browse(new URI(url));
188 | } catch (IOException | URISyntaxException e) {
189 | e.printStackTrace();
190 | }
191 | }
192 |
193 | public static void addJSON(JsonObject base, JsonObject add){
194 | //Iterate over all entries in add
195 | for(String addKey : add.keySet()){
196 | //get the current entry as an object
197 | JsonElement addElement = add.get(addKey);
198 | //If the base tag does not have this tag yet, add this tag to base
199 | if(!base.has(addKey)){
200 | base.add(addKey, addElement);
201 | }else{ //If it does exist, try to merge depending on the type
202 | addJsonByType(base.get(addKey), addElement, (e) -> base.add(addKey, e));
203 | }
204 | }
205 | }
206 |
207 | private static void addJsonByType(JsonElement baseElement, JsonElement addElement, Consumer overwriteAction){
208 | //The simplest is a primitive, it is just replaced:
209 | if(baseElement.isJsonPrimitive() && addElement.isJsonPrimitive()){
210 | overwriteAction.accept(addElement);
211 | //If they are both objects, recursively call this merge method
212 | }else if(baseElement.isJsonObject() && addElement.isJsonObject()){
213 | addJSON(baseElement.getAsJsonObject(), addElement.getAsJsonObject());
214 | //If they are arrays, find markers or append
215 | }else if(baseElement.isJsonArray() && addElement.isJsonArray()){
216 | //save the elements in new variables
217 | JsonArray addArray = addElement.getAsJsonArray();
218 | JsonArray baseArray = baseElement.getAsJsonArray();
219 | //Then iterate over the added array
220 | for(JsonElement addArrayElement : addArray){
221 | //Handle depending on type
222 | //If it is an object, look for markers
223 | if(addArrayElement.isJsonObject()){
224 | //Check for CPWHERE (overrides CPINDEX) and if it is an object
225 | if(addArrayElement.getAsJsonObject().has("CPWHERE") &&
226 | addArrayElement.getAsJsonObject().get("CPWHERE").isJsonObject()){
227 | JsonObject whereObject = addArrayElement.getAsJsonObject().get("CPWHERE").getAsJsonObject();
228 | //Test if where has the Strings 'id' and 'value'
229 | if(whereObject.has("id") && whereObject.get("id").isJsonPrimitive() &&
230 | whereObject.has("value") && whereObject.get("value").isJsonPrimitive()){
231 | String id = whereObject.get("id").getAsString();
232 | String value = whereObject.get("value").getAsString();
233 | //Now find an entry in the base array that has id==value
234 | for(int i = 0; i < baseArray.size(); i++){
235 | JsonElement baseArrayElement = baseArray.get(i);
236 | //The element has to be an object and has to have a tag called id that is a primitive
237 | if(baseArrayElement.isJsonObject() && baseArrayElement.getAsJsonObject().has(id) &&
238 | baseArrayElement.getAsJsonObject().get(id).isJsonPrimitive()){
239 | //Value has to be equal
240 | if(baseArrayElement.getAsJsonObject().get(id).getAsString().equals(value)){
241 | //We found a tag
242 | //Now remove the CPWHERE part
243 | addArrayElement.getAsJsonObject().remove("CPWHERE");
244 | final int index = i; //This is necessary, lambda doesn't like non-finals
245 | addJsonByType(baseArrayElement, addArrayElement, (e) -> baseArray.set(index, e));
246 | //Then break out of the for loop, only the first item should be modified
247 | break;
248 | }
249 | }
250 | }
251 | }else{
252 | System.err.println("Json Parser - Add: Found CPWHERE tag, but 'id' or 'value' tags were missing");
253 | }
254 | //if the reqired fields do not exist, do nothing
255 |
256 | //Check for CPINDEX next and if it is a primitive
257 | }else if(addArrayElement.getAsJsonObject().has("CPINDEX") &&
258 | addArrayElement.getAsJsonObject().get("CPINDEX").isJsonPrimitive()){
259 | //Check if the index is within range
260 | int index = addArrayElement.getAsJsonObject().get("CPINDEX").getAsInt();
261 | if(index >= 0 && index < baseArray.size()){
262 | //Get the element from the base array
263 | JsonElement baseArrayElement = baseArray.get(index);
264 | //Also remove the CPINDEX tag before merging
265 | addArrayElement.getAsJsonObject().remove("CPINDEX");
266 | addJsonByType(baseArrayElement, addArrayElement, (e) -> baseArray.set(index, e));
267 | }else{
268 | System.err.println("Json Parser - Add: Found CPINDEX tag, but index was out of bounds");
269 | }
270 | //If the index is out of bounds, do nothing
271 | //If no marker is found, simply append
272 | }else{
273 | baseArray.add(addArrayElement);
274 | }
275 | //Primitives and arrays (can you even put arrays in arrays in json?) cannot have a marker and are appended
276 | }else{
277 | baseArray.add(addArrayElement);
278 | }
279 | }
280 | //If they are different types, they are also replaced
281 | }else{
282 | overwriteAction.accept(addElement);
283 | }
284 | }
285 |
286 |
287 | private static void removeJsonByType(JsonElement baseElement, JsonElement removeElement, Runnable deleteAction){
288 | //Basic behavior: if any is primitive, delete
289 | //If both are objects, recursive call removeJson
290 | //If both are arrays, go through entries and apply this
291 | //If they are different types, delete
292 | if(baseElement.isJsonPrimitive() && removeElement.isJsonPrimitive()){
293 | deleteAction.run();
294 | }else if(baseElement.isJsonObject() && removeElement.isJsonObject()){
295 | removeJSON(baseElement.getAsJsonObject(), removeElement.getAsJsonObject());
296 | }else if(baseElement.isJsonArray() && removeElement.isJsonArray()){
297 | //Iterate over the remove array entries
298 | JsonArray removeArray = removeElement.getAsJsonArray();
299 | JsonArray baseArray = baseElement.getAsJsonArray();
300 | for(JsonElement removeArrayElement : removeArray){
301 | if(removeArrayElement.isJsonObject()){
302 | if(removeArrayElement.getAsJsonObject().has("CPINDEX") &&
303 | removeArrayElement.getAsJsonObject().get("CPINDEX").isJsonPrimitive()){
304 | final int index = removeArrayElement.getAsJsonObject().get("CPINDEX").getAsInt();
305 | if(index >= 0 && index < baseArray.size()){
306 | removeJsonByType(baseArray.get(index), removeArrayElement, () -> baseArray.remove(index));
307 | }else{
308 | System.err.println("Json Parser - Remove: Found CPINDEX tag, but index was out of bounds");
309 | }
310 | }else if(removeArrayElement.getAsJsonObject().has("CPWHERE") &&
311 | removeArrayElement.getAsJsonObject().get("CPWHERE").isJsonObject()){
312 | JsonObject whereObject = removeArrayElement.getAsJsonObject().get("CPWHERE").getAsJsonObject();
313 | if(whereObject.has("id") && whereObject.get("id").isJsonPrimitive() &&
314 | whereObject.has("value") && whereObject.get("value").isJsonPrimitive()){
315 | String id = whereObject.get("id").getAsString();
316 | String value = whereObject.get("value").getAsString();
317 | //Now iterate over basearray and find tag to remove
318 | for(int i = 0; i < baseArray.size(); i++){
319 | JsonElement baseArrayElement = baseArray.get(i);
320 | //can only delete objects bc only objects can have id==value
321 | if(baseArrayElement.isJsonObject() && baseArrayElement.getAsJsonObject().has(id) &&
322 | baseArrayElement.getAsJsonObject().get(id).isJsonPrimitive() &&
323 | baseArrayElement.getAsJsonObject().get(id).getAsString().equals(value)){
324 | //We have a match, now delete it
325 | final int index = i;
326 | removeJsonByType(baseArrayElement, removeArrayElement, () -> baseArray.remove(index));
327 | break;
328 | }
329 | }
330 | }else{
331 | System.err.println("Json Parser - Remove: Found CPWHERE tag, but 'id' or 'value' tags were missing");
332 | }
333 | }
334 | }
335 | //If you don't give me a hint on what entry you mean, I'm afraid I can't do anything for you.
336 | }
337 | }else{
338 | deleteAction.run();
339 | }
340 | }
341 |
342 | public static void removeJSON(JsonObject base, JsonObject remove){
343 | //iterate over all entries in remove
344 | for(String removeKey : remove.keySet()){
345 | //If base does not have this tag, just ignore, else handle depending on type
346 | if(base.has(removeKey)){
347 | JsonElement removeElement = remove.get(removeKey);
348 | JsonElement baseElement = base.get(removeKey);
349 | removeJsonByType(baseElement, removeElement, () -> base.remove(removeKey));
350 | }
351 | }
352 | }
353 |
354 | public static boolean contains(Iterable l, Predicate test){
355 | for(T t : l){
356 | if(test.test(t))
357 | return true;
358 | }
359 | return false;
360 | }
361 |
362 | public static T getFirst(Iterable l, Predicate test){
363 | for(T t : l){
364 | if(test.test(t))
365 | return t;
366 | }
367 | return null;
368 | }
369 |
370 | public static byte[] concat(byte[] a, byte[] b){
371 | byte[] c = new byte[a.length + b.length];
372 | System.arraycopy(a, 0, c, 0, a.length);
373 | System.arraycopy(b, 0, c, a.length, b.length);
374 | return c;
375 | }
376 |
377 | public static byte[] encodeInt(int num){
378 | return new byte[] {
379 | (byte)(num),
380 | (byte)(num >>> 8),
381 | (byte)(num >>> 16),
382 | (byte)(num >>> 24)};
383 | }
384 |
385 | public static int decodeInt(byte[] num){
386 | if(num.length != 4)
387 | throw new NumberFormatException("Array size must be 4");
388 | return ((num[0]) & 0xFF) + ((num[1] & 0xFF) << 8) +
389 | ((num[2] & 0xFF) << 16) + ((num[3] & 0xFF) << 24);
390 | }
391 |
392 | public static void writeInt(ByteArrayOutputStream out, int i) throws IOException{
393 | out.write(encodeInt(i));
394 | }
395 |
396 | public static void writeString(ByteArrayOutputStream out, String s, byte terminator) throws IOException{
397 | out.write((byte) s.length());
398 | out.write(s.getBytes());
399 | out.write(terminator);
400 | }
401 |
402 | }
403 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/annotation/Async.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker.annotation;
2 |
3 | import static java.lang.annotation.RetentionPolicy.CLASS;
4 | import static java.lang.annotation.ElementType.METHOD;
5 |
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | * Annotated methods should be called asynchonously, because they may be blocking the thread for some time.
11 | * @author Lars
12 | *
13 | */
14 | @Retention(CLASS)
15 | @Target(METHOD)
16 | public @interface Async {
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/annotation/Calculated.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker.annotation;
2 |
3 | import static java.lang.annotation.ElementType.METHOD;
4 | import static java.lang.annotation.RetentionPolicy.CLASS;
5 |
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | * The object returned by the annotated method is newly cfeated eery time the method is called
11 | * This method should only be used in cases where it isn't obvoius that the returned object is not
12 | * a field or stored in a variable.
13 | * @author Lars b.
14 | * @version 1.0
15 | */
16 | @Retention(CLASS)
17 | @Target(METHOD)
18 | public @interface Calculated {
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/annotation/Shortcut.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker.annotation;
2 |
3 | import static java.lang.annotation.ElementType.METHOD;
4 | import static java.lang.annotation.RetentionPolicy.CLASS;
5 |
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | * Annotated methods are shortcuts for other methods. The name of a method call
11 | * with the same result is stored in the value parameter of this annotation.
12 | * @author Lars b.
13 | * @version 1.0
14 | */
15 | @Retention(CLASS)
16 | @Target(METHOD)
17 | public @interface Shortcut {
18 | String value();
19 | }
20 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/annotation/Unmodifiable.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker.annotation;
2 |
3 | import static java.lang.annotation.ElementType.METHOD;
4 | import static java.lang.annotation.RetentionPolicy.CLASS;
5 |
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | * Annotated methods return unmodifiable/immutable objects.
11 | * @author Lars B.
12 | * @version 1.0
13 | */
14 | @Retention(CLASS)
15 | @Target(METHOD)
16 | public @interface Unmodifiable {
17 | }
18 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/controls/CheckBoxList.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker.controls;
2 |
3 | import java.awt.Component;
4 | import java.awt.event.MouseAdapter;
5 | import java.awt.event.MouseEvent;
6 |
7 | import javax.swing.DefaultListModel;
8 | import javax.swing.JCheckBox;
9 | import javax.swing.JList;
10 | import javax.swing.ListCellRenderer;
11 | import javax.swing.ListModel;
12 | import javax.swing.ListSelectionModel;
13 | import javax.swing.UIManager;
14 | import javax.swing.border.Border;
15 | import javax.swing.border.EmptyBorder;
16 |
17 | public class CheckBoxList extends JList{
18 | private static final long serialVersionUID = 2796368191296898045L;
19 |
20 | protected static Border noFocusBorder =
21 | new EmptyBorder(1, 1, 1, 1);
22 |
23 | public CheckBoxList()
24 | {
25 | super(new DefaultListModel<>());
26 |
27 | setCellRenderer(new CellRenderer());
28 |
29 | addMouseListener(new MouseAdapter()
30 | {
31 | public void mousePressed(MouseEvent e)
32 | {
33 | int index = locationToIndex(e.getPoint());
34 |
35 | if (index != -1) {
36 | JCheckBox checkbox = (JCheckBox)
37 | getModel().getElementAt(index);
38 | checkbox.setSelected(
39 | !checkbox.isSelected());
40 | repaint();
41 | }
42 | }
43 | }
44 | );
45 |
46 | setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
47 | }
48 |
49 | public void addCheckbox(JCheckBox checkBox) {
50 | ListModel currentList = this.getModel();
51 | JCheckBox[] newList = new JCheckBox[currentList.getSize() + 1];
52 | for (int i = 0; i < currentList.getSize(); i++) {
53 | newList[i] = (JCheckBox) currentList.getElementAt(i);
54 | }
55 | newList[newList.length - 1] = checkBox;
56 | setListData(newList);
57 | }
58 |
59 | protected class CellRenderer implements ListCellRenderer
60 | {
61 | public Component getListCellRendererComponent(
62 | JList extends JCheckBox> list, JCheckBox value, int index,
63 | boolean isSelected, boolean cellHasFocus)
64 | {
65 | JCheckBox checkbox = (JCheckBox) value;
66 | checkbox.setBackground(isSelected ?
67 | getSelectionBackground() : getBackground());
68 | checkbox.setForeground(isSelected ?
69 | getSelectionForeground() : getForeground());
70 | checkbox.setEnabled(isEnabled());
71 | checkbox.setFont(getFont());
72 | checkbox.setFocusPainted(false);
73 | checkbox.setBorderPainted(true);
74 | checkbox.setBorder(isSelected ?
75 | UIManager.getBorder(
76 | "List.focusCellHighlightBorder") : noFocusBorder);
77 | return checkbox;
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/controls/JAudioPlayer.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker.controls;
2 |
3 | import java.awt.Dimension;
4 | import java.awt.FlowLayout;
5 | import java.awt.event.MouseEvent;
6 | import java.awt.event.MouseListener;
7 | import java.util.concurrent.TimeUnit;
8 |
9 | import javax.sound.sampled.Clip;
10 | import javax.sound.sampled.LineEvent;
11 | import javax.sound.sampled.LineListener;
12 | import javax.swing.JButton;
13 | import javax.swing.JLabel;
14 | import javax.swing.JPanel;
15 | import javax.swing.JSlider;
16 | import javax.swing.Timer;
17 |
18 | import dev.lb.sound.ogg.JOrbisDecoder;
19 |
20 | public class JAudioPlayer extends JPanel implements MouseListener{
21 | private static final long serialVersionUID = -7802517197319750907L;
22 |
23 | private Clip sound;
24 |
25 | private JButton playpause;
26 | private JButton stop;
27 | private JSlider progress;
28 |
29 | private JPanel contentHolder;
30 | private JLabel done;
31 | private JLabel total;
32 | private Timer barUpdater;
33 |
34 | private boolean playing;
35 | private boolean pressing;
36 |
37 | public JAudioPlayer(){
38 | super();
39 | contentHolder = new JPanel();
40 | contentHolder.setLayout(new FlowLayout());
41 |
42 | playpause = new JButton("Play");
43 | playpause.addActionListener((e) -> {
44 | if(playing){
45 | pause();
46 | }else{
47 | play();
48 | }
49 | });
50 | playpause.setPreferredSize(new Dimension(100, playpause.getPreferredSize().height));
51 | stop = new JButton("Stop");
52 | stop.addActionListener((e) -> {
53 | stop(true);
54 | });
55 | stop.setPreferredSize(new Dimension(100, stop.getPreferredSize().height));
56 |
57 | progress = new JSlider();
58 | progress.setPreferredSize(new Dimension(200,progress.getPreferredSize().height));
59 | progress.addMouseListener(this);
60 | progress.setSnapToTicks(false);
61 |
62 | barUpdater = new Timer(50, (e) -> updateSlider());
63 |
64 | done = new JLabel("00:00");
65 | total = new JLabel("00:00");
66 |
67 | pressing = false;
68 |
69 |
70 | contentHolder.add(playpause);
71 | contentHolder.add(done);
72 | contentHolder.add(progress);
73 | contentHolder.add(total);
74 | contentHolder.add(stop);
75 | this.add(contentHolder);
76 | }
77 |
78 | public JAudioPlayer(Clip clip){
79 | this();
80 | this.setClip(clip);
81 | }
82 |
83 | public void play(){
84 | playpause.setText("Pause");
85 | if(sound == null || playing)
86 | return;
87 | playing = true;
88 | barUpdater.start();
89 | new Thread(sound::start).start();
90 | updateSlider();
91 | }
92 |
93 | public void pause(){
94 | if(sound == null || !playing)
95 | return;
96 | barUpdater.stop();
97 | playpause.setText("Play");
98 | playing = false;
99 | sound.stop();
100 | updateSlider();
101 | }
102 |
103 | public void stop(boolean force){
104 | playpause.setText("Play");
105 | if(sound == null || (!playing && !force))
106 | return;
107 | barUpdater.stop();
108 | sound.stop();
109 | sound.flush();
110 | sound.setFramePosition(0);
111 | playing = false;
112 | updateSlider();
113 | }
114 |
115 |
116 | public void setClip(Clip c){
117 | reset();
118 | sound = c;
119 | sound.addLineListener(new LineListener(){
120 | public void update(LineEvent e){
121 | if(e.getType() == LineEvent.Type.STOP){
122 | stop(false);
123 | }
124 | }
125 | });
126 | progress.setMinimum(0);
127 | progress.setMaximum(sound.getFrameLength());
128 | int sec = JOrbisDecoder.getLengthInSeconds(sound);
129 | total.setText(String.format("%02d:%02d",
130 | TimeUnit.SECONDS.toMinutes(sec),
131 | TimeUnit.SECONDS.toSeconds(sec) -
132 | TimeUnit.MINUTES.toSeconds(TimeUnit.SECONDS.toMinutes(sec))));
133 | }
134 |
135 | public void updateSlider(){
136 | if(sound == null)
137 | return;
138 | if(!pressing)
139 | progress.setValue(sound.getFramePosition());
140 | int sec = JOrbisDecoder.getPlayTimeInSeconds(sound);
141 | done.setText(String.format("%02d:%02d",
142 | TimeUnit.SECONDS.toMinutes(sec),
143 | TimeUnit.SECONDS.toSeconds(sec) -
144 | TimeUnit.MINUTES.toSeconds(TimeUnit.SECONDS.toMinutes(sec))));
145 | done.repaint();
146 | }
147 |
148 | public void reset(){
149 | if(sound == null)
150 | return;
151 | barUpdater.stop();
152 | sound.stop();
153 | sound.flush();
154 | sound = null;
155 | playing = false;
156 | progress.setValue(0);
157 | done.setText("00:00");
158 | total.setText("00:00");
159 | }
160 |
161 | @Override
162 | public void mouseClicked(MouseEvent e) {}
163 | @Override
164 | public void mouseEntered(MouseEvent e) {}
165 | @Override
166 | public void mouseExited(MouseEvent e) {}
167 | @Override
168 | public void mousePressed(MouseEvent e) {
169 | pressing = true;
170 | }
171 |
172 |
173 | @Override
174 | public void mouseReleased(MouseEvent e) {
175 | if(sound != null && progress.getValue() != sound.getFramePosition())
176 | sound.setFramePosition(progress.getValue());
177 | pressing = false;
178 | }
179 |
180 | @Override
181 | public void setPreferredSize(Dimension preferredSize) {}
182 |
183 | }
184 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/controls/JDraggableScrollPane.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker.controls;
2 |
3 | import java.awt.Component;
4 | import java.awt.Point;
5 | import java.awt.Rectangle;
6 | import java.awt.event.MouseEvent;
7 | import java.awt.event.MouseListener;
8 | import java.awt.event.MouseMotionListener;
9 |
10 | import javax.swing.JComponent;
11 | import javax.swing.JScrollPane;
12 | import javax.swing.JViewport;
13 |
14 | public class JDraggableScrollPane extends JScrollPane implements MouseMotionListener, MouseListener{
15 | private static final long serialVersionUID = -3429376543623295066L;
16 |
17 | private Point currentDrag;
18 |
19 | public JDraggableScrollPane(Component view, int vsbPolicy, int hsbPolicy) {
20 | super(view, vsbPolicy, hsbPolicy);
21 | this.getViewport().getView().addMouseMotionListener(this);
22 | this.getViewport().getView().addMouseListener(this);
23 | }
24 |
25 | public JDraggableScrollPane(Component view) {
26 | super(view);
27 | if(this.getViewport().getView() != null){
28 | this.getViewport().getView().addMouseMotionListener(this);
29 | this.getViewport().getView().addMouseListener(this);
30 | }
31 | }
32 |
33 | @Override
34 | public void mouseDragged(MouseEvent e) {
35 | if (currentDrag != null) {
36 | JViewport viewPort = getViewport();
37 | if (viewPort != null) {
38 | int deltaX = currentDrag.x - e.getX();
39 | int deltaY = currentDrag.y - e.getY();
40 |
41 | Rectangle view = viewPort.getViewRect();
42 | view.x += deltaX;
43 | view.y += deltaY;
44 |
45 | ((JComponent) getViewport().getView()).scrollRectToVisible(view);
46 | }
47 | }
48 | }
49 |
50 | @Override
51 | public void mousePressed(MouseEvent e) {
52 | currentDrag = new Point(e.getPoint());
53 | }
54 |
55 | @Override
56 | public void mouseMoved(MouseEvent e) {}
57 | @Override
58 | public void mouseEntered(MouseEvent e) {}
59 | @Override
60 | public void mouseExited(MouseEvent e) {}
61 | @Override
62 | public void mouseClicked(MouseEvent e) {}
63 | @Override
64 | public void mouseReleased(MouseEvent e) {}
65 | }
66 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/controls/JHistoryTextField.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker.controls;
2 |
3 | import java.awt.event.KeyEvent;
4 | import java.awt.event.KeyListener;
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | import javax.swing.JTextField;
9 |
10 | public class JHistoryTextField extends JTextField implements KeyListener{
11 | private static final long serialVersionUID = 4185648576613819237L;
12 |
13 | private List history;
14 | private int historyIndex;
15 | private String temp;
16 |
17 | public JHistoryTextField(){
18 | super();
19 | history = new ArrayList<>();
20 | historyIndex = 0;
21 | addKeyListener(this);
22 | }
23 |
24 | public void clearHistory(){
25 | history.clear();
26 | }
27 |
28 | public void addHistory(){
29 | history.add(getText());
30 | temp = "";
31 | historyIndex = history.size();
32 | setText("");
33 | }
34 |
35 | public void updateText(){
36 | setText(history.get(historyIndex));
37 | }
38 |
39 | @Override
40 | public void keyPressed(KeyEvent e) {
41 | if(e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_KP_UP){
42 | historyIndex--;
43 | if(history.isEmpty()) return;
44 | if(historyIndex == history.size() - 1){
45 | temp = getText();
46 | }
47 | if(historyIndex < 0){
48 | historyIndex = 0;
49 | }
50 | updateText();
51 | }else if(e.getKeyCode() == KeyEvent.VK_DOWN || e.getKeyCode() == KeyEvent.VK_KP_DOWN){
52 | historyIndex++;
53 | if(historyIndex == history.size()){
54 | setText(temp);
55 | }else if(historyIndex > history.size()){
56 | historyIndex = history.size();
57 | }else{
58 | updateText();
59 | }
60 | }
61 | }
62 |
63 | @Override
64 | public void keyReleased(KeyEvent e) {}
65 |
66 | @Override
67 | public void keyTyped(KeyEvent e) {}
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/controls/JImageViewer.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker.controls;
2 |
3 | import java.awt.Dimension;
4 | import java.awt.Graphics;
5 | import java.awt.Image;
6 | import java.awt.event.MouseWheelEvent;
7 | import java.awt.event.MouseWheelListener;
8 | import java.awt.image.BufferedImage;
9 |
10 | import javax.swing.JPanel;
11 |
12 | public class JImageViewer extends JPanel implements MouseWheelListener{
13 | private static final long serialVersionUID = -4208234595443517732L;
14 |
15 | private Image image;
16 | private Image overlay;
17 |
18 | private double scrollFactor = 1.0D;
19 |
20 | public JImageViewer(Image mainImage) {
21 | image = mainImage;
22 | this.addMouseWheelListener(this);
23 | }
24 |
25 | @Override
26 | protected void paintComponent(Graphics g) {
27 | super.paintComponent(g);
28 | g.drawImage(image, 0, 0, (int) (getPreferredSize().width * scrollFactor), (int) (getPreferredSize().height * scrollFactor), getBackground(), this);
29 | if(overlay != null){
30 | g.drawImage(overlay, 0, 0, (int) (getPreferredSize().width * scrollFactor), (int) (getPreferredSize().height * scrollFactor), getBackground(), this);
31 | }
32 | }
33 |
34 | protected Image getMainImage(){
35 | return image;
36 | }
37 |
38 | public Image getOverlay() {
39 | return overlay;
40 | }
41 |
42 | public void setOverlay(Image overlay) {
43 | this.overlay = overlay;
44 | }
45 |
46 |
47 | @Override
48 | public Dimension getPreferredSize(){
49 | return new Dimension((int) (image.getWidth(this) * scrollFactor), (int) (image.getHeight(this) * scrollFactor));
50 | }
51 |
52 | @Override
53 | public Dimension getMinimumSize(){
54 | return getPreferredSize();
55 | }
56 |
57 | @Override
58 | public Dimension getMaximumSize(){
59 | return getPreferredSize();
60 | }
61 |
62 | public void setOverlay(BufferedImage overlay2) {
63 | overlay = overlay2;
64 | }
65 |
66 | @Override
67 | public void mouseWheelMoved(MouseWheelEvent e) {
68 | int clicks = e.getWheelRotation();
69 | if(clicks < 0 && scrollFactor < 5){ //ZOOM IN
70 | scrollFactor *= 1.25D;
71 | }else if(clicks > 0 && scrollFactor > 0.2){ //ZOOM OUT
72 | scrollFactor /= 1.25D;
73 | }
74 | this.revalidate();
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/controls/JSpriteViewer.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker.controls;
2 |
3 | import java.awt.Dimension;
4 | import java.awt.Graphics;
5 | import java.awt.event.MouseWheelEvent;
6 | import java.awt.image.BufferedImage;
7 |
8 | public class JSpriteViewer extends JImageViewer{
9 | private static final long serialVersionUID = -5063070371711033414L;
10 | public static final BufferedImage EMPTY_SPRITE;
11 | static{
12 | EMPTY_SPRITE = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
13 | EMPTY_SPRITE.createGraphics().drawString("No sprite", 20, 50);
14 | }
15 |
16 | private BufferedImage currentSprite = EMPTY_SPRITE;
17 | private BufferedImage currentSpriteF = EMPTY_SPRITE;
18 | private boolean filter;
19 | private int cx, cy, cw, ch;
20 |
21 | public JSpriteViewer(BufferedImage mainImage, BufferedImage filterImage) {
22 | super(mainImage);
23 | this.setOverlay(filterImage);
24 | }
25 |
26 | @Override
27 | public Dimension getPreferredSize() {
28 | return new Dimension(0, 0);
29 | }
30 |
31 | public void setSprite(int x, int y, int width, int height){
32 | currentSprite = ((BufferedImage) getMainImage()).getSubimage(x, y, width, height);
33 | currentSpriteF = getOverlay() == null ? null : ((BufferedImage) getOverlay()).getSubimage(x, y, width, height);
34 | cx = x;
35 | cy = y;
36 | cw = width;
37 | ch = height;
38 | this.repaint();
39 | }
40 |
41 | public void setNoSprite(){
42 | currentSprite = EMPTY_SPRITE;
43 | cx = 0;
44 | cy = 0;
45 | cw = 0;
46 | ch = 0;
47 | this.repaint();
48 | }
49 |
50 | public void setUseFilter(boolean useFilter){
51 | filter = useFilter;
52 | repaint();
53 | }
54 |
55 | @Override
56 | public void mouseWheelMoved(MouseWheelEvent e) {
57 | //No scrolling allowed
58 | }
59 |
60 | @Override
61 | protected void paintComponent(Graphics g) {
62 | double ratio = ((double) currentSprite.getHeight(this) / (double) currentSprite.getWidth(this));
63 | double thisRatio = ((double) getHeight() / (double) getWidth());
64 | int scaleWidth, scaleHeight, startX, startY;
65 | if(ratio < thisRatio){//Wide
66 | scaleWidth = getWidth();
67 | scaleHeight = (int) (getWidth() * ratio);
68 | startX = 0;
69 | startY = (getHeight() - scaleHeight) / 2;
70 | }else{//Tall
71 | scaleWidth = (int) (getHeight() * (1D / ratio));
72 | scaleHeight = getHeight();
73 | startX = (getWidth() - scaleWidth) / 2;
74 | startY = 0;
75 | }
76 | g.clearRect(0, 0, getWidth(), getHeight());
77 | g.drawImage(filter ? currentSpriteF : currentSprite, startX, startY, scaleWidth, scaleHeight, this);
78 | }
79 |
80 | public int getCx() {
81 | return cx;
82 | }
83 |
84 | public int getCy() {
85 | return cy;
86 | }
87 |
88 | public int getCw() {
89 | return cw;
90 | }
91 |
92 | public int getCh() {
93 | return ch;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/dev/lb/cellpacker/controls/LaunchWindow.java:
--------------------------------------------------------------------------------
1 | package dev.lb.cellpacker.controls;
2 |
3 | import java.awt.BorderLayout;
4 | import java.awt.Dimension;
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.IOException;
8 | import java.nio.file.Files;
9 | import java.util.ArrayList;
10 | import java.util.HashMap;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | import javax.swing.DefaultListModel;
15 | import javax.swing.ImageIcon;
16 | import javax.swing.JButton;
17 | import javax.swing.JCheckBox;
18 | import javax.swing.JFrame;
19 | import javax.swing.JOptionPane;
20 | import javax.swing.JPanel;
21 | import javax.swing.JScrollPane;
22 | import javax.swing.ListModel;
23 | import javax.swing.border.EmptyBorder;
24 |
25 | import com.google.gson.Gson;
26 | import com.google.gson.JsonElement;
27 | import com.google.gson.JsonObject;
28 | import com.google.gson.JsonParser;
29 |
30 | import dev.lb.cellpacker.CellPackerMain;
31 | import dev.lb.cellpacker.Utils;
32 | import dev.lb.cellpacker.structure.ResourceCategory;
33 | import dev.lb.cellpacker.structure.ResourceFile;
34 | import dev.lb.cellpacker.structure.Script;
35 | import dev.lb.cellpacker.structure.resource.JsonResource;
36 |
37 | public class LaunchWindow extends JFrame{
38 | private static final long serialVersionUID = 2286569184156822247L;
39 |
40 | public static final int NO_PROBLEM = 0;
41 | public static final int NEED_SETUP = 1;
42 | public static final int NOT_DEADCELLS = 2;
43 |
44 | private Map chk2script = new HashMap<>();
45 | @SuppressWarnings("unused")
46 | private boolean update;
47 | private JButton launch;
48 | private JButton launchgl;
49 | private JButton reload;
50 | private JButton pack;
51 | private JButton help;
52 | private CheckBoxList chl;
53 |
54 | public LaunchWindow(boolean update){
55 | super("CellPacker Launcher 2.1");
56 | this.update = update;
57 |
58 | JPanel content = new JPanel(new BorderLayout());
59 | JPanel buttons = new JPanel();
60 | //buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));
61 | chl = new CheckBoxList();
62 | content.add(new JScrollPane(chl), BorderLayout.CENTER);
63 | launch = new JButton("Start Dead Cells");
64 | launchgl = new JButton("Start Dead Cells (OpenGL - Legacy)");
65 | pack = new JButton("Start CellPacker");
66 | help = new JButton("Help / About");
67 | launch.setBorder(new EmptyBorder(5, 10, 5, 10));
68 | launchgl.setBorder(new EmptyBorder(5, 10, 5, 10));
69 | pack.setBorder(new EmptyBorder(5, 10, 5, 10));
70 | help.setBorder(new EmptyBorder(5, 10, 5, 10));
71 | launch.setPreferredSize(new Dimension(150, 50));
72 | launchgl.setPreferredSize(new Dimension(150, 50));
73 | reload = new JButton("Reload scripts");
74 | reload.addActionListener((e) -> {
75 | chl.setModel(new DefaultListModel<>());
76 | if(setupCorrect()){
77 | reloadScripts();
78 | }else{
79 | chl.addCheckbox(new JCheckBox(""));
80 | }
81 | });
82 | reload.setPreferredSize(new Dimension(150, 50));
83 | pack.setPreferredSize(new Dimension(150, 50));
84 | help.setPreferredSize(new Dimension(150, 50));
85 | help.addActionListener((e) -> {
86 | Utils.showAboutDialog("For more information read the Readme on the github page:
https://github.com/ReBuilders101/CellPacker/blob/master/README.md", "About / Help", "https://github.com/ReBuilders101/CellPacker/blob/master/README.md");
87 | });
88 | pack.addActionListener((e) -> {
89 | CellPackerMain.mainFrame = new MainWindow();
90 | CellPackerMain.mainFrame.setVisible(true);
91 | CellPackerMain.mainFrame.setIconImage(new ImageIcon(CellPackerMain.class.getResource("/resources/ico.png")).getImage());
92 | this.dispose();
93 | });
94 | launch.addActionListener((e) -> {
95 | launch(false);
96 | });
97 | launchgl.addActionListener((e) -> {
98 | launch(true);
99 | });
100 | buttons.add(launch);
101 | buttons.add(launchgl);
102 | buttons.add(pack);
103 | buttons.add(reload);
104 | buttons.add(help);
105 | content.add(buttons, BorderLayout.SOUTH);
106 |
107 | if(setupCorrect()){
108 | reloadScripts();
109 | }else{
110 | chl.addCheckbox(new JCheckBox(""));
111 | }
112 |
113 |
114 | this.add(content);
115 | this.setPreferredSize(new Dimension(800, 300));
116 | this.setMinimumSize(new Dimension(400, 200));
117 | this.pack();
118 | this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
119 | }
120 |
121 | private void reloadScripts(){
122 | //Get all available patches
123 | File patchDir = new File("./cpscripts");
124 | for(File script : patchDir.listFiles((e) -> e.getPath().endsWith(".patch") && e.isFile())){
125 | //read file to json
126 | byte[] data = new byte[(int) script.length()];
127 | try(FileInputStream fis = new FileInputStream(script)){
128 | fis.read(data);
129 | } catch (IOException e1) {
130 | e1.printStackTrace();
131 | }
132 | String json = new String(data);
133 | if(Utils.isJsonValid(json)){ //Can be parsed
134 | JsonElement jsonElement = new JsonParser().parse(json);
135 | if(jsonElement.isJsonObject()){
136 | String name = "";
137 | String desc = "";
138 | if(jsonElement.getAsJsonObject().has("info") && jsonElement.getAsJsonObject().get("info").isJsonObject()){
139 | System.out.println("Found info section");
140 | JsonObject info = jsonElement.getAsJsonObject().get("info").getAsJsonObject();
141 | name = info.has("name") ? info.get("name").getAsString() : script.getName();
142 | desc = info.has("desc") ? info.get("desc").getAsString() : "No description";
143 | }else{
144 | System.out.println("Found no info section");
145 | //Add box by file name
146 | name = script.getName();
147 | desc = "No description";
148 | }
149 | JsonObject add = new JsonObject();
150 | if(jsonElement.getAsJsonObject().has("add") && jsonElement.getAsJsonObject().get("add").isJsonObject()){
151 | add = jsonElement.getAsJsonObject().get("add").getAsJsonObject();
152 | }
153 | JsonObject remove = new JsonObject();
154 | if(jsonElement.getAsJsonObject().has("remove") && jsonElement.getAsJsonObject().get("remove").isJsonObject()){
155 | add = jsonElement.getAsJsonObject().get("remove").getAsJsonObject();
156 | }
157 | Script sc = new Script(name, desc, add, remove);
158 | JCheckBox box = new JCheckBox(name);
159 | box.setToolTipText(desc);
160 | chk2script.put(box, sc);
161 | chl.addCheckbox(box);
162 | }else{
163 | JOptionPane.showMessageDialog(this, "The file " + script.getName() + " is not a valid JSON Script and cannot be used as a script", "Error", JOptionPane.ERROR_MESSAGE);
164 | }
165 | }else{
166 | JOptionPane.showMessageDialog(this, "The file " + script.getName() + " is not valid JSON and cannot be used as a script", "Error", JOptionPane.ERROR_MESSAGE);
167 | }
168 |
169 | //chl.addCheckbox(new JCheckBox(script.getName().substring(0, script.getName().lastIndexOf('.'))));
170 | }
171 | }
172 |
173 | private void launch(boolean gl){
174 | //Patch resource
175 | ResourceFile rf = ResourceFile.fromFile(new File("./res.pak.cpbackup"));
176 | JsonResource datacdb = (JsonResource) rf.getRootContainer().getResource("data.cdb");
177 | JsonObject cdbJson = new JsonParser().parse((String) datacdb.getContent()).getAsJsonObject();
178 | ListModel model = chl.getModel();
179 | List