Merge branch 'feature/ocelot-card' into develop

This commit is contained in:
Fingercomp 2023-07-13 19:43:20 +07:00
commit 82de79bdd1
No known key found for this signature in database
GPG Key ID: BBC71CEE45D86E37
13 changed files with 780 additions and 290 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -154,4 +154,11 @@ Grid3DColor = #303030
Grid3DPosX = #c9205a Grid3DPosX = #c9205a
Grid3DNegX = #6e213b Grid3DNegX = #6e213b
Grid3DPosZ = #255cba Grid3DPosZ = #255cba
Grid3DNegZ = #264170 Grid3DNegZ = #264170
LogBackground = #222222
LogBorder = #666666
LogEntryBackground = #cccccc
LogEntryBorder = #888888
OcelotCardTooltip = #c1905f

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 116 KiB

View File

@ -1,275 +1,276 @@
BackgroundPattern 0 0 304 304 BackgroundPattern 0 0 304 304
BarSegment 493 479 16 4 BarSegment 29 499 16 4
Empty 473 277 16 16 Empty 153 381 16 16
EmptySlot 233 379 18 18 EmptySlot 256 330 18 18
Knob 447 208 50 50 Knob 692 0 50 50
KnobCenter 233 305 50 50 KnobCenter 743 0 50 50
KnobLimits 284 305 50 50 KnobLimits 794 0 50 50
ShadowBorder 497 305 1 24 ShadowBorder 0 538 1 24
ShadowCorner 372 305 24 24 ShadowCorner 153 305 24 24
TabArrow 85 496 8 14 TabArrow 0 484 8 14
blocks/Generic 490 277 16 16 blocks/Generic 170 381 16 16
blocks/HologramEffect 277 498 4 4 blocks/HologramEffect 8 547 4 4
blocks/HologramProjector1Top 486 129 16 16 blocks/HologramProjector1Top 187 381 16 16
blocks/HologramProjector2Top 486 146 16 16 blocks/HologramProjector2Top 204 381 16 16
blocks/HologramProjectorSide 486 163 16 16 blocks/HologramProjectorSide 221 381 16 16
buttons/BottomDrawerClose 252 379 18 18 buttons/BottomDrawerClose 275 330 18 18
buttons/BottomDrawerOpen 271 379 18 18 buttons/BottomDrawerOpen 294 330 18 18
buttons/OpenFMRadioCloseOff 248 496 7 8 buttons/OpenFMRadioCloseOff 48 510 7 8
buttons/OpenFMRadioCloseOn 256 496 7 8 buttons/OpenFMRadioCloseOn 56 510 7 8
buttons/OpenFMRadioRedstoneOff 203 496 8 8 buttons/OpenFMRadioRedstoneOff 3 510 8 8
buttons/OpenFMRadioRedstoneOn 212 496 8 8 buttons/OpenFMRadioRedstoneOn 12 510 8 8
buttons/OpenFMRadioStartOff 397 305 24 24 buttons/OpenFMRadioStartOff 178 305 24 24
buttons/OpenFMRadioStartOn 422 305 24 24 buttons/OpenFMRadioStartOn 203 305 24 24
buttons/OpenFMRadioStopOff 447 305 24 24 buttons/OpenFMRadioStopOff 228 305 24 24
buttons/OpenFMRadioStopOn 472 305 24 24 buttons/OpenFMRadioStopOn 253 305 24 24
buttons/OpenFMRadioVolumeDownOff 130 496 10 10 buttons/OpenFMRadioVolumeDownOff 9 484 10 10
buttons/OpenFMRadioVolumeDownOn 141 496 10 10 buttons/OpenFMRadioVolumeDownOn 20 484 10 10
buttons/OpenFMRadioVolumeUpOff 152 496 10 10 buttons/OpenFMRadioVolumeUpOff 31 484 10 10
buttons/OpenFMRadioVolumeUpOn 163 496 10 10 buttons/OpenFMRadioVolumeUpOn 42 484 10 10
buttons/PowerOff 290 379 18 18 buttons/PowerOff 313 330 18 18
buttons/PowerOn 309 379 18 18 buttons/PowerOn 332 330 18 18
icons/Antenna 486 180 16 16 icons/Antenna 238 381 16 16
icons/ArrowRight 0 411 16 16 icons/ArrowRight 255 381 16 16
icons/AspectRatio 17 411 16 16 icons/AspectRatio 272 381 16 16
icons/ButtonCheck 447 259 17 17 icons/ButtonCheck 153 363 17 17
icons/ButtonClipboard 465 259 17 17 icons/ButtonClipboard 171 363 17 17
icons/ButtonRandomize 483 259 17 17 icons/ButtonRandomize 189 363 17 17
icons/CPU 34 411 16 16 icons/CPU 289 381 16 16
icons/Card 51 411 16 16 icons/Card 306 381 16 16
icons/Close 0 496 15 14 icons/Close 0 451 15 14
icons/Code 68 411 16 16 icons/Code 323 381 16 16
icons/ComponentBus 85 411 16 16 icons/ComponentBus 340 381 16 16
icons/Copy 102 411 16 16 icons/Copy 357 381 16 16
icons/Cross 119 411 16 16 icons/Cross 374 381 16 16
icons/Delete 136 411 16 16 icons/Delete 391 381 16 16
icons/DragLMB 302 356 21 14 icons/DragLMB 351 330 21 14
icons/DragRMB 324 356 21 14 icons/DragRMB 373 330 21 14
icons/EEPROM 153 411 16 16 icons/EEPROM 408 381 16 16
icons/Edit 170 411 16 16 icons/Edit 425 381 16 16
icons/Eject 187 411 16 16 icons/Eject 442 381 16 16
icons/File 204 411 16 16 icons/File 459 381 16 16
icons/Floppy 221 411 16 16 icons/Floppy 476 381 16 16
icons/Folder 238 411 16 16 icons/Folder 493 381 16 16
icons/FolderSlash 255 411 16 16 icons/FolderSlash 510 381 16 16
icons/Grid 233 356 22 22 icons/Grid 187 330 22 22
icons/GridOff 256 356 22 22 icons/GridOff 210 330 22 22
icons/HDD 272 411 16 16 icons/HDD 527 381 16 16
icons/Home 279 356 22 22 icons/Home 233 330 22 22
icons/LMB 61 496 11 14 icons/LMB 71 466 11 14
icons/Label 289 411 16 16 icons/Label 544 381 16 16
icons/LinesHorizontal 306 411 16 16 icons/LinesHorizontal 561 381 16 16
icons/Link 323 411 16 16 icons/Link 578 381 16 16
icons/LinkSlash 340 411 16 16 icons/LinkSlash 595 381 16 16
icons/Memory 357 411 16 16 icons/Memory 612 381 16 16
icons/Microchip 374 411 16 16 icons/Microchip 629 381 16 16
icons/NA 391 411 16 16 icons/NA 646 381 16 16
icons/NotificationError 94 496 11 11 icons/NotificationError 95 466 11 11
icons/NotificationInfo 106 496 11 11 icons/NotificationInfo 107 466 11 11
icons/NotificationWarning 118 496 11 11 icons/NotificationWarning 119 466 11 11
icons/Pin 16 496 14 14 icons/Pin 26 466 14 14
icons/Plus 408 411 16 16 icons/Plus 663 381 16 16
icons/Power 425 411 16 16 icons/Power 680 381 16 16
icons/RMB 73 496 11 14 icons/RMB 83 466 11 14
icons/Restart 442 411 16 16 icons/Restart 697 381 16 16
icons/Save 459 411 16 16 icons/Save 714 381 16 16
icons/SaveAs 476 411 16 16 icons/SaveAs 731 381 16 16
icons/Server 493 411 16 16 icons/Server 748 381 16 16
icons/SettingsSound 447 277 12 17 icons/SettingsSound 0 466 12 17
icons/SettingsUI 460 277 12 17 icons/SettingsUI 13 466 12 17
icons/Tier0 0 428 16 16 icons/Tier0 765 381 16 16
icons/Tier1 17 428 16 16 icons/Tier1 782 381 16 16
icons/Tier2 34 428 16 16 icons/Tier2 799 381 16 16
icons/Tiers 51 428 16 16 icons/Tiers 816 381 16 16
icons/Unpin 31 496 14 14 icons/Unpin 41 466 14 14
icons/WaveLFSR 335 344 24 10 icons/WaveLFSR 121 434 24 10
icons/WaveNoise 360 344 24 10 icons/WaveNoise 146 434 24 10
icons/WaveSawtooth 385 344 24 10 icons/WaveSawtooth 171 434 24 10
icons/WaveSine 410 344 24 10 icons/WaveSine 196 434 24 10
icons/WaveSquare 435 344 24 10 icons/WaveSquare 221 434 24 10
icons/WaveTriangle 460 344 24 10 icons/WaveTriangle 246 434 24 10
icons/Window 68 428 16 16 icons/Window 833 381 16 16
icons/WireArrowLeft 264 496 4 8 icons/WireArrowLeft 2 538 4 8
icons/WireArrowRight 269 496 4 8 icons/WireArrowRight 7 538 4 8
items/APU0 305 208 16 96 items/APU0 85 305 16 96
items/APU1 322 208 16 96 items/APU1 102 305 16 96
items/APU2 339 208 16 96 items/APU2 119 305 16 96
items/CPU0 85 428 16 16 items/CPU0 850 381 16 16
items/CPU1 102 428 16 16 items/CPU1 867 381 16 16
items/CPU2 119 428 16 16 items/CPU2 884 381 16 16
items/CardBase 136 428 16 16 items/CardBase 901 381 16 16
items/CircuitBoard 153 428 16 16 items/CircuitBoard 918 381 16 16
items/ComponentBus0 170 428 16 16 items/ComponentBus0 935 381 16 16
items/ComponentBus1 187 428 16 16 items/ComponentBus1 952 381 16 16
items/ComponentBus2 204 428 16 16 items/ComponentBus2 969 381 16 16
items/ComponentBus3 221 428 16 16 items/ComponentBus3 986 381 16 16
items/DataCard0 434 0 16 128 items/DataCard0 0 305 16 128
items/DataCard1 451 0 16 128 items/DataCard1 17 305 16 128
items/DataCard2 468 0 16 128 items/DataCard2 34 305 16 128
items/DebugCard 238 428 16 16 items/DebugCard 1003 381 16 16
items/DiskDriveMountable 255 428 16 16 items/DiskDriveMountable 278 305 16 16
items/EEPROM 272 428 16 16 items/EEPROM 295 305 16 16
items/FloppyDisk_dyeBlack 289 428 16 16 items/FloppyDisk_dyeBlack 312 305 16 16
items/FloppyDisk_dyeBlue 306 428 16 16 items/FloppyDisk_dyeBlue 329 305 16 16
items/FloppyDisk_dyeBrown 323 428 16 16 items/FloppyDisk_dyeBrown 346 305 16 16
items/FloppyDisk_dyeCyan 340 428 16 16 items/FloppyDisk_dyeCyan 363 305 16 16
items/FloppyDisk_dyeGray 357 428 16 16 items/FloppyDisk_dyeGray 380 305 16 16
items/FloppyDisk_dyeGreen 374 428 16 16 items/FloppyDisk_dyeGreen 397 305 16 16
items/FloppyDisk_dyeLightBlue 391 428 16 16 items/FloppyDisk_dyeLightBlue 414 305 16 16
items/FloppyDisk_dyeLightGray 408 428 16 16 items/FloppyDisk_dyeLightGray 431 305 16 16
items/FloppyDisk_dyeLime 425 428 16 16 items/FloppyDisk_dyeLime 448 305 16 16
items/FloppyDisk_dyeMagenta 442 428 16 16 items/FloppyDisk_dyeMagenta 465 305 16 16
items/FloppyDisk_dyeOrange 459 428 16 16 items/FloppyDisk_dyeOrange 482 305 16 16
items/FloppyDisk_dyePink 476 428 16 16 items/FloppyDisk_dyePink 499 305 16 16
items/FloppyDisk_dyePurple 493 428 16 16 items/FloppyDisk_dyePurple 516 305 16 16
items/FloppyDisk_dyeRed 0 445 16 16 items/FloppyDisk_dyeRed 533 305 16 16
items/FloppyDisk_dyeWhite 17 445 16 16 items/FloppyDisk_dyeWhite 550 305 16 16
items/FloppyDisk_dyeYellow 34 445 16 16 items/FloppyDisk_dyeYellow 567 305 16 16
items/GraphicsCard0 51 445 16 16 items/GraphicsCard0 584 305 16 16
items/GraphicsCard1 68 445 16 16 items/GraphicsCard1 601 305 16 16
items/GraphicsCard2 85 445 16 16 items/GraphicsCard2 618 305 16 16
items/HardDiskDrive0 102 445 16 16 items/HardDiskDrive0 635 305 16 16
items/HardDiskDrive1 119 445 16 16 items/HardDiskDrive1 652 305 16 16
items/HardDiskDrive2 136 445 16 16 items/HardDiskDrive2 669 305 16 16
items/InternetCard 338 305 16 32 items/InternetCard 153 330 16 32
items/LinkedCard 356 208 16 96 items/LinkedCard 136 305 16 96
items/Memory0 153 445 16 16 items/Memory0 686 305 16 16
items/Memory1 170 445 16 16 items/Memory1 703 305 16 16
items/Memory2 187 445 16 16 items/Memory2 720 305 16 16
items/Memory3 204 445 16 16 items/Memory3 737 305 16 16
items/Memory4 221 445 16 16 items/Memory4 754 305 16 16
items/Memory5 238 445 16 16 items/Memory5 771 305 16 16
items/NetworkCard 255 445 16 16 items/NetworkCard 788 305 16 16
items/RedstoneCard0 272 445 16 16 items/OcelotCard 51 305 16 128
items/RedstoneCard1 289 445 16 16 items/RedstoneCard0 805 305 16 16
items/SelfDestructingCard 355 305 16 32 items/RedstoneCard1 822 305 16 16
items/Server0 306 445 16 16 items/SelfDestructingCard 170 330 16 32
items/Server1 323 445 16 16 items/Server0 839 305 16 16
items/Server2 340 445 16 16 items/Server1 856 305 16 16
items/Server3 357 445 16 16 items/Server2 873 305 16 16
items/SoundCard 485 0 16 128 items/Server3 890 305 16 16
items/WirelessNetworkCard0 374 445 16 16 items/SoundCard 68 305 16 128
items/WirelessNetworkCard1 391 445 16 16 items/WirelessNetworkCard0 907 305 16 16
light-panel/BookmarkLeft 328 379 18 14 items/WirelessNetworkCard1 924 305 16 16
light-panel/BookmarkRight 346 356 20 14 light-panel/BookmarkLeft 102 434 18 14
light-panel/BorderB 282 498 4 4 light-panel/BookmarkRight 207 363 20 14
light-panel/BorderL 372 498 4 2 light-panel/BorderB 13 547 4 4
light-panel/BorderR 287 498 4 4 light-panel/BorderL 103 547 4 2
light-panel/BorderT 292 498 4 4 light-panel/BorderR 18 547 4 4
light-panel/CornerBL 297 498 4 4 light-panel/BorderT 23 547 4 4
light-panel/CornerBR 302 498 4 4 light-panel/CornerBL 28 547 4 4
light-panel/CornerTL 307 498 4 4 light-panel/CornerBR 33 547 4 4
light-panel/CornerTR 312 498 4 4 light-panel/CornerTL 38 547 4 4
light-panel/Fill 507 484 2 2 light-panel/CornerTR 43 547 4 4
light-panel/Vent 335 305 2 38 light-panel/Fill 6 558 2 2
nodes/Cable 221 496 8 8 light-panel/Vent 0 499 2 38
nodes/Camera 408 445 16 16 nodes/Cable 21 510 8 8
nodes/Chest 46 496 14 14 nodes/Camera 941 305 16 16
nodes/HologramProjector0 425 445 16 16 nodes/Chest 56 466 14 14
nodes/HologramProjector1 442 445 16 16 nodes/HologramProjector0 958 305 16 16
nodes/IronNoteBlock 459 445 16 16 nodes/HologramProjector1 975 305 16 16
nodes/Lamp 476 445 16 16 nodes/IronNoteBlock 992 305 16 16
nodes/LampFrame 493 445 16 16 nodes/Lamp 85 402 16 16
nodes/LampGlow 305 0 128 128 nodes/LampFrame 102 402 16 16
nodes/NewNode 0 462 16 16 nodes/LampGlow 305 106 128 128
nodes/NoteBlock 17 462 16 16 nodes/NewNode 119 402 16 16
nodes/OpenFMRadio 34 462 16 16 nodes/NoteBlock 136 402 16 16
nodes/Relay 51 462 16 16 nodes/OpenFMRadio 153 402 16 16
nodes/computer/Activity 68 462 16 16 nodes/Relay 170 402 16 16
nodes/computer/Default 85 462 16 16 nodes/computer/Activity 187 402 16 16
nodes/computer/Error 102 462 16 16 nodes/computer/Default 204 402 16 16
nodes/computer/On 119 462 16 16 nodes/computer/Error 221 402 16 16
nodes/disk-drive/Activity 136 462 16 16 nodes/computer/On 238 402 16 16
nodes/disk-drive/Default 153 462 16 16 nodes/disk-drive/Activity 255 402 16 16
nodes/disk-drive/Floppy 170 462 16 16 nodes/disk-drive/Default 272 402 16 16
nodes/rack/Default 187 462 16 16 nodes/disk-drive/Floppy 289 402 16 16
nodes/rack/Empty 204 462 16 16 nodes/rack/Default 306 402 16 16
nodes/rack/drive/0/Activity 221 462 16 16 nodes/rack/Empty 323 402 16 16
nodes/rack/drive/0/Default 238 462 16 16 nodes/rack/drive/0/Activity 340 402 16 16
nodes/rack/drive/0/Floppy 255 462 16 16 nodes/rack/drive/0/Default 357 402 16 16
nodes/rack/drive/1/Activity 272 462 16 16 nodes/rack/drive/0/Floppy 374 402 16 16
nodes/rack/drive/1/Default 289 462 16 16 nodes/rack/drive/1/Activity 391 402 16 16
nodes/rack/drive/1/Floppy 306 462 16 16 nodes/rack/drive/1/Default 408 402 16 16
nodes/rack/drive/2/Activity 323 462 16 16 nodes/rack/drive/1/Floppy 425 402 16 16
nodes/rack/drive/2/Default 340 462 16 16 nodes/rack/drive/2/Activity 442 402 16 16
nodes/rack/drive/2/Floppy 357 462 16 16 nodes/rack/drive/2/Default 459 402 16 16
nodes/rack/drive/3/Activity 374 462 16 16 nodes/rack/drive/2/Floppy 476 402 16 16
nodes/rack/drive/3/Default 391 462 16 16 nodes/rack/drive/3/Activity 493 402 16 16
nodes/rack/drive/3/Floppy 408 462 16 16 nodes/rack/drive/3/Default 510 402 16 16
nodes/rack/drive/Floppy 425 462 16 16 nodes/rack/drive/3/Floppy 527 402 16 16
nodes/rack/server/0/Activity 442 462 16 16 nodes/rack/drive/Floppy 544 402 16 16
nodes/rack/server/0/Default 459 462 16 16 nodes/rack/server/0/Activity 561 402 16 16
nodes/rack/server/0/Error 476 462 16 16 nodes/rack/server/0/Default 578 402 16 16
nodes/rack/server/0/On 493 462 16 16 nodes/rack/server/0/Error 595 402 16 16
nodes/rack/server/1/Activity 0 479 16 16 nodes/rack/server/0/On 612 402 16 16
nodes/rack/server/1/Default 17 479 16 16 nodes/rack/server/1/Activity 629 402 16 16
nodes/rack/server/1/Error 34 479 16 16 nodes/rack/server/1/Default 646 402 16 16
nodes/rack/server/1/On 51 479 16 16 nodes/rack/server/1/Error 663 402 16 16
nodes/rack/server/2/Activity 68 479 16 16 nodes/rack/server/1/On 680 402 16 16
nodes/rack/server/2/Default 85 479 16 16 nodes/rack/server/2/Activity 697 402 16 16
nodes/rack/server/2/Error 102 479 16 16 nodes/rack/server/2/Default 714 402 16 16
nodes/rack/server/2/On 119 479 16 16 nodes/rack/server/2/Error 731 402 16 16
nodes/rack/server/3/Activity 136 479 16 16 nodes/rack/server/2/On 748 402 16 16
nodes/rack/server/3/Default 153 479 16 16 nodes/rack/server/3/Activity 765 402 16 16
nodes/rack/server/3/Error 170 479 16 16 nodes/rack/server/3/Default 782 402 16 16
nodes/rack/server/3/On 187 479 16 16 nodes/rack/server/3/Error 799 402 16 16
nodes/screen/BottomLeft 204 479 16 16 nodes/rack/server/3/On 816 402 16 16
nodes/screen/BottomMiddle 221 479 16 16 nodes/screen/BottomLeft 833 402 16 16
nodes/screen/BottomRight 238 479 16 16 nodes/screen/BottomMiddle 850 402 16 16
nodes/screen/ColumnBottom 255 479 16 16 nodes/screen/BottomRight 867 402 16 16
nodes/screen/ColumnMiddle 272 479 16 16 nodes/screen/ColumnBottom 884 402 16 16
nodes/screen/ColumnTop 289 479 16 16 nodes/screen/ColumnMiddle 901 402 16 16
nodes/screen/Middle 306 479 16 16 nodes/screen/ColumnTop 918 402 16 16
nodes/screen/MiddleLeft 323 479 16 16 nodes/screen/Middle 935 402 16 16
nodes/screen/MiddleRight 340 479 16 16 nodes/screen/MiddleLeft 952 402 16 16
nodes/screen/PowerOnOverlay 357 479 16 16 nodes/screen/MiddleRight 969 402 16 16
nodes/screen/RowLeft 374 479 16 16 nodes/screen/PowerOnOverlay 986 402 16 16
nodes/screen/RowMiddle 391 479 16 16 nodes/screen/RowLeft 1003 402 16 16
nodes/screen/RowRight 408 479 16 16 nodes/screen/RowMiddle 0 434 16 16
nodes/screen/Standalone 425 479 16 16 nodes/screen/RowRight 17 434 16 16
nodes/screen/TopLeft 442 479 16 16 nodes/screen/Standalone 34 434 16 16
nodes/screen/TopMiddle 459 479 16 16 nodes/screen/TopLeft 51 434 16 16
nodes/screen/TopRight 476 479 16 16 nodes/screen/TopMiddle 68 434 16 16
panel/BorderB 317 498 4 4 nodes/screen/TopRight 85 434 16 16
panel/BorderL 377 498 4 2 panel/BorderB 48 547 4 4
panel/BorderR 322 498 4 4 panel/BorderL 108 547 4 2
panel/BorderT 327 498 4 4 panel/BorderR 53 547 4 4
panel/CornerBL 332 498 4 4 panel/BorderT 58 547 4 4
panel/CornerBR 337 498 4 4 panel/CornerBL 63 547 4 4
panel/CornerTL 342 498 4 4 panel/CornerBR 68 547 4 4
panel/CornerTR 347 498 4 4 panel/CornerTL 73 547 4 4
panel/Fill 493 489 2 2 panel/CornerTR 78 547 4 4
particles/Note 192 496 7 10 panel/Fill 9 558 2 2
screen/BorderB 274 496 2 8 particles/Note 21 499 7 10
screen/BorderT 200 496 2 10 screen/BorderB 5 547 2 8
screen/CornerBL 230 496 8 8 screen/BorderT 2 547 2 10
screen/CornerBR 239 496 8 8 screen/CornerBL 30 510 8 8
screen/CornerTL 174 496 8 10 screen/CornerBR 39 510 8 8
screen/CornerTR 183 496 8 10 screen/CornerTL 3 499 8 10
window/BorderDark 510 479 1 4 screen/CornerTR 12 499 8 10
window/BorderLight 493 484 1 4 window/BorderDark 2 558 1 4
window/CornerBL 352 498 4 4 window/BorderLight 4 558 1 4
window/CornerBR 357 498 4 4 window/CornerBL 83 547 4 4
window/CornerTL 362 498 4 4 window/CornerBR 88 547 4 4
window/CornerTR 367 498 4 4 window/CornerTL 93 547 4 4
window/OpenFMRadio 0 305 232 105 window/CornerTR 98 547 4 4
window/case/Motherboard 406 129 79 70 window/OpenFMRadio 305 0 232 105
window/rack/Lines 373 208 73 91 window/case/Motherboard 612 0 79 70
window/rack/Motherboard 305 129 100 78 window/rack/Lines 538 0 73 91
window/rack/NetworkBack 496 489 1 2 window/rack/Motherboard 434 106 100 78
window/rack/NetworkBottom 498 489 1 2 window/rack/NetworkBack 20 552 1 2
window/rack/NetworkConnector 500 489 1 2 window/rack/NetworkBottom 22 552 1 2
window/rack/NetworkLeft 502 489 1 2 window/rack/NetworkConnector 24 552 1 2
window/rack/NetworkRight 504 489 1 2 window/rack/NetworkLeft 26 552 1 2
window/rack/NetworkTop 506 489 1 2 window/rack/NetworkRight 28 552 1 2
window/rack/NodeBack 277 496 5 1 window/rack/NetworkTop 30 552 1 2
window/rack/NodeBottom 283 496 5 1 window/rack/NodeBack 113 547 5 1
window/rack/NodeLeft 289 496 5 1 window/rack/NodeBottom 119 547 5 1
window/rack/NodeRight 295 496 5 1 window/rack/NodeLeft 125 547 5 1
window/rack/NodeTop 301 496 5 1 window/rack/NodeRight 131 547 5 1
window/rack/SideBack 495 484 1 3 window/rack/NodeTop 137 547 5 1
window/rack/SideBottom 497 484 1 3 window/rack/SideBack 8 552 1 3
window/rack/SideConnector 499 484 1 3 window/rack/SideBottom 10 552 1 3
window/rack/SideLeft 501 484 1 3 window/rack/SideConnector 12 552 1 3
window/rack/SideRight 503 484 1 3 window/rack/SideLeft 14 552 1 3
window/rack/SideTop 505 484 1 3 window/rack/SideRight 16 552 1 3
window/rack/SideTop 18 552 1 3

View File

@ -0,0 +1,61 @@
package ocelot.desktop.entity
import ocelot.desktop.entity.OcelotCard.LogEvent
import totoro.ocelot.brain.Constants
import totoro.ocelot.brain.entity.machine.{Arguments, Callback, Context}
import totoro.ocelot.brain.entity.traits.DeviceInfo.{DeviceAttribute, DeviceClass}
import totoro.ocelot.brain.entity.traits.{DeviceInfo, Entity, Environment, Tiered, result}
import totoro.ocelot.brain.event.{EventBus, NodeEvent}
import totoro.ocelot.brain.network.{Network, Node, Visibility}
import totoro.ocelot.brain.util.Tier
import totoro.ocelot.brain.util.Tier.Tier
import java.time.Instant
class OcelotCard extends Entity with Environment with DeviceInfo with Tiered {
override val node: Node = Network.newNode(this, Visibility.Neighbors)
.withComponent("ocelot", Visibility.Neighbors)
.create()
override def tier: Tier = Tier.One
private final lazy val deviceInfo = Map(
DeviceAttribute.Class -> DeviceClass.Generic,
DeviceAttribute.Description -> "Yarn ball manipulator",
DeviceAttribute.Vendor -> Constants.DeviceInfo.DefaultVendor,
DeviceAttribute.Product -> "Catbus",
)
override def getDeviceInfo: Map[String, String] = deviceInfo
@Callback(direct = true, doc = """function(message: string) -- Logs a message to the Ocelot console.""")
def log(context: Context, args: Arguments): Array[AnyRef] = {
val message = args.checkString(0)
EventBus.send(LogEvent(node.address, message))
result()
}
@Callback(direct = true, doc = """function(): integer -- Returns the current Unix timestamp (UTC, in milliseconds).""")
def getTimestamp(context: Context, args: Arguments): Array[AnyRef] = {
result(Instant.now().toEpochMilli)
}
@Callback(direct = true, doc = """function(): integer -- Returns a high-resolution timer value (in nanoseconds).""")
def getInstant(context: Context, args: Arguments): Array[AnyRef] = {
result(System.nanoTime())
}
@Callback(direct = true, doc = """function(): number -- Returns the remaining call budget.""")
def getRemainingCallBudget(context: Context, args: Arguments): Array[AnyRef] = {
result(context.getRemainingCallBudget)
}
@Callback(direct = true, doc = """function(): number -- Returns the maximum call budget.""")
def getMaxCallBudget(context: Context, args: Arguments): Array[AnyRef] = {
result(context.getMaxCallBudget)
}
}
object OcelotCard {
case class LogEvent(address: String, message: String) extends NodeEvent
}

View File

@ -220,7 +220,7 @@ class Graphics(private var scalingFactor: Float) extends Logging with Resource {
def text(x: Float, y: Float, text: String, shrink: Int = 0): Unit = { def text(x: Float, y: Float, text: String, shrink: Int = 0): Unit = {
var ox = x var ox = x
for (c <- text) { text.codePoints().forEach { c =>
char(ox, y, c) char(ox, y, c)
ox += _font.charWidth(c) - shrink ox += _font.charWidth(c) - shrink
} }
@ -329,7 +329,7 @@ class Graphics(private var scalingFactor: Float) extends Logging with Resource {
val uvTransform = Transform2D.translate(spriteRect.x, spriteRect.y) >> val uvTransform = Transform2D.translate(spriteRect.x, spriteRect.y) >>
(if (fixUV) (if (fixUV)
Transform2D.scale(spriteRect.w - 0.25f / 512, spriteRect.h - 0.25f / 512) Transform2D.scale(spriteRect.w - 0.25f / 1024, spriteRect.h - 0.25f / 1024)
else else
Transform2D.scale(spriteRect.w, spriteRect.h)) Transform2D.scale(spriteRect.w, spriteRect.h))

View File

@ -60,6 +60,8 @@ object IconSource {
val SelfDestructingCard: IconSource = IconSource("items/SelfDestructingCard", animation = Some(Animations.SelfDestructingCard)) val SelfDestructingCard: IconSource = IconSource("items/SelfDestructingCard", animation = Some(Animations.SelfDestructingCard))
val OcelotCard: IconSource = IconSource("items/OcelotCard", animation = Some(Animations.OcelotCard))
val HardDiskDrive: Tier => IconSource = { tier => val HardDiskDrive: Tier => IconSource = { tier =>
IconSource(s"items/HardDiskDrive${tier.id}") IconSource(s"items/HardDiskDrive${tier.id}")
} }
@ -101,6 +103,9 @@ object IconSource {
(0, 4f), (1, 4f), (2, 4f), (3, 4f), (4, 4f), (5, 4f), (6, 4f), (7, 4f)) (0, 4f), (1, 4f), (2, 4f), (3, 4f), (4, 4f), (5, 4f), (6, 4f), (7, 4f))
val SelfDestructingCard: Animation = Array((0, 4f), (1, 4f)) val SelfDestructingCard: Animation = Array((0, 4f), (1, 4f))
val OcelotCard: Animation = Array(
(0, 12f), (1, 4f), (2, 4f), (3, 4f), (4, 5f), (5, 6f), (0, 9f), (6, 4f), (7, 3f))
} }
// ----------------------- Ocelot interface icons ----------------------- // ----------------------- Ocelot interface icons -----------------------

View File

@ -139,6 +139,7 @@ object Items extends Logging {
} }
registerSingleton(SoundCardItem.Factory) registerSingleton(SoundCardItem.Factory)
registerSingleton(SelfDestructingCardItem.Factory) registerSingleton(SelfDestructingCardItem.Factory)
registerSingleton(OcelotCardItem.Factory)
registerTiered("Server", Tier.One to Tier.Creative)(new ServerItem.Factory(_)) registerTiered("Server", Tier.One to Tier.Creative)(new ServerItem.Factory(_))
registerTiered("Component bus", Tier.One to Tier.Creative)(new ComponentBusItem.Factory(_)) registerTiered("Component bus", Tier.One to Tier.Creative)(new ComponentBusItem.Factory(_))

View File

@ -0,0 +1,104 @@
package ocelot.desktop.inventory.item
import ocelot.desktop.ColorScheme
import ocelot.desktop.color.Color
import ocelot.desktop.entity.OcelotCard
import ocelot.desktop.graphics.IconSource
import ocelot.desktop.inventory.item.OcelotCardItem.MessagesTag
import ocelot.desktop.inventory.traits.{CardItem, ComponentItem, PersistableItem}
import ocelot.desktop.inventory.{Item, ItemFactory, ItemRecoverer}
import ocelot.desktop.ui.event.BrainEvent
import ocelot.desktop.ui.widget.card.OcelotCardWindow
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry}
import ocelot.desktop.ui.widget.window.Windowed
import totoro.ocelot.brain.nbt.ExtendedNBT.extendNBTTagList
import totoro.ocelot.brain.nbt.{NBT, NBTBase, NBTTagCompound, NBTTagString}
import totoro.ocelot.brain.util.Tier
import totoro.ocelot.brain.util.Tier.Tier
import scala.collection.IndexedSeqView
import scala.collection.mutable.ArrayBuffer
import scala.jdk.CollectionConverters.BufferHasAsJava
class OcelotCardItem(val ocelotCard: OcelotCard)
extends Item
with ComponentItem
with PersistableItem
with CardItem
with Windowed[OcelotCardWindow] {
private val _messages: ArrayBuffer[String] = ArrayBuffer.empty
def messages: IndexedSeqView[String] = _messages.view
eventHandlers += {
case BrainEvent(OcelotCard.LogEvent(_, message)) =>
addMessage(message)
}
override def createWindow(): OcelotCardWindow = new OcelotCardWindow(this)
override def component: OcelotCard = ocelotCard
override def tooltipNameColor: Color = ColorScheme("OcelotCardTooltip")
override def fillRmbMenu(menu: ContextMenu): Unit = {
menu.addEntry(ContextMenuEntry("Open console", IconSource.Window) {
window.open()
})
menu.addSeparator()
super.fillRmbMenu(menu)
}
override def load(nbt: NBTTagCompound): Unit = {
super.load(nbt)
clear()
addMessages(nbt.getTagList(MessagesTag, NBT.TAG_STRING).iterator[NBTTagString].map(_.getString))
}
override def save(nbt: NBTTagCompound): Unit = {
super.save(nbt)
nbt.setTagList(MessagesTag, _messages.map(new NBTTagString(_).asInstanceOf[NBTBase]).asJava)
}
override def factory: ItemFactory = OcelotCardItem.Factory
def clear(): Unit = {
_messages.clear()
window.onMessagesCleared()
}
private def addMessage(message: String): Unit = {
_messages += message
window.onMessagesAdded(1)
}
private def addMessages(messages: Iterator[String]): Unit = {
val currentSize = this._messages.length
this._messages ++= messages
window.onMessagesAdded(this._messages.length - currentSize)
}
}
object OcelotCardItem {
val MessagesTag = "messages"
object Factory extends ItemFactory {
override type I = OcelotCardItem
override def itemClass: Class[I] = classOf
override def name: String = "Ocelot Card"
override def tier: Option[Tier] = Some(Tier.One)
override def icon: IconSource = IconSource.OcelotCard
override def build(): OcelotCardItem = new OcelotCardItem(new OcelotCard)
override def recoverers: Iterable[ItemRecoverer[_, _]] = Nil
}
}

View File

@ -1,28 +1,26 @@
package ocelot.desktop.node package ocelot.desktop.node
import ocelot.desktop.inventory.{Item, SyncedInventory} import ocelot.desktop.inventory.SyncedInventory
import ocelot.desktop.inventory.traits.ComponentItem
import ocelot.desktop.ui.event.Event import ocelot.desktop.ui.event.Event
import totoro.ocelot.brain.entity.traits.{Entity, Environment} import totoro.ocelot.brain.entity.traits.{Entity, Environment}
abstract class SyncedInventoryEntityNode(entity: Entity with Environment) abstract class SyncedInventoryEntityNode(entity: Entity with Environment)
extends EntityNode(entity) extends EntityNode(entity)
with SyncedInventory with SyncedInventory {
{
override def shouldReceiveEventsFor(address: String): Boolean = override def shouldReceiveEventsFor(address: String): Boolean =
super.shouldReceiveEventsFor(address) || super.shouldReceiveEventsFor(address) ||
brainInventory.inventory.entities.exists { inventoryIterator
case env: Environment => env.node.address == address .flatMap(_.get)
} .collect { case item: ComponentItem => item }
.exists(_.component.node.address == address)
override def handleEvent(event: Event): Unit = { override def handleEvent(event: Event): Unit = {
super.handleEvent(event) super.handleEvent(event)
inventoryIterator.foreach(slot => for (slot <- inventoryIterator; item <- slot.get) {
slot.get match { item.handleEvent(event)
case Some(item: Item) => }
item.handleEvent(event)
case _ =>
}
)
} }
} }

View File

@ -0,0 +1,94 @@
package ocelot.desktop.ui.widget
import ocelot.desktop.ColorScheme
import ocelot.desktop.geometry.{Padding2D, Size2D}
import ocelot.desktop.graphics.Graphics
import ocelot.desktop.ui.layout.{Layout, LinearLayout}
import ocelot.desktop.ui.widget.LogWidget.{BorderThickness, EntryPadding}
import ocelot.desktop.util.{DrawUtils, Orientation}
import scala.collection.immutable.ArraySeq
abstract class LogWidget extends Widget {
override protected val layout: Layout = new LinearLayout(this, orientation = Orientation.Vertical)
private val messageListWidget = new Widget {
override protected val layout: Layout = new LinearLayout(this, orientation = Orientation.Vertical)
}
children :+= new PaddingBox(
new ScrollView(messageListWidget),
Padding2D.equal(BorderThickness),
)
protected def messages: Iterable[String]
protected def textWidth: Int
override def minimumSize: Size2D = Size2D(
textWidth * 8 +
2 * BorderThickness + // entry border (left + right)
2 * EntryPadding +
2 * BorderThickness, // outer border (left + right)
16 +
2 * BorderThickness + // entry border (top + bottom)
2 * EntryPadding +
2 * BorderThickness, // outer border (top + bottom)
)
def onMessagesAdded(count: Int): Unit = {
for (message <- messages.drop(messages.size - count)) {
messageListWidget.children :+= new Entry(message)
}
recalculateBoundsAndRelayout()
}
def onMessagesCleared(): Unit = {
messageListWidget.children = ArraySeq.empty
recalculateBoundsAndRelayout()
}
override def draw(g: Graphics): Unit = {
g.rect(bounds, ColorScheme("LogBackground"))
DrawUtils.ring(g, bounds.x, bounds.y, bounds.w, bounds.h, BorderThickness, ColorScheme("LogBorder"))
super.draw(g)
}
private class Entry(val message: String) extends Widget {
override protected val layout: Layout = new LinearLayout(this, orientation = Orientation.Vertical)
children :+= new PaddingBox(
new Text {
override def text: String = message
override def wrapWidth: Option[Int] = Some(LogWidget.this.textWidth)
},
Padding2D.equal(EntryPadding + BorderThickness),
)
override def draw(g: Graphics): Unit = {
val innerBounds = bounds.inflate(-EntryPadding)
val ringBounds = innerBounds.inflate(BorderThickness)
g.rect(innerBounds, ColorScheme("LogEntryBackground"))
DrawUtils.ring(
g,
ringBounds.x,
ringBounds.y,
ringBounds.w,
ringBounds.h,
BorderThickness,
ColorScheme("LogEntryBorder"),
)
super.draw(g)
}
}
}
object LogWidget {
val BorderThickness = 2
val EntryPadding = 4
}

View File

@ -0,0 +1,169 @@
package ocelot.desktop.ui.widget
import ocelot.desktop.ColorScheme
import ocelot.desktop.color.Color
import ocelot.desktop.geometry.Size2D
import ocelot.desktop.graphics.Graphics
import ocelot.desktop.ui.widget.Text.{CharHeight, getWidth, wrap}
import totoro.ocelot.brain.util.FontUtils
import scala.collection.mutable.ArrayBuffer
class Text extends Widget {
def text: String = ""
private var cachedText = ""
private var cachedWrapWidth = None: Option[Int]
private var cachedLines = ArrayBuffer.empty[String]
private var cachedWidth = 0
def color: Color = ColorScheme("Label")
def wrapWidth: Option[Int] = None
private def recomputeIfNeeded(): Unit = {
if (text != cachedText || cachedWrapWidth != wrapWidth) {
recomputeProperties()
}
}
final def textWidth: Int = {
recomputeIfNeeded()
cachedWidth
}
final def textHeight: Int = {
recomputeIfNeeded()
cachedLines.length
}
final def textLines: Iterable[String] = {
recomputeIfNeeded()
cachedLines
}
override def minimumSize: Size2D = Size2D(textWidth, CharHeight * (textHeight max 1))
override def maximumSize: Size2D = minimumSize.copy(width = Float.PositiveInfinity)
override def draw(g: Graphics): Unit = {
g.background = Color.Transparent
g.foreground = color
for ((line, idx) <- textLines.zipWithIndex) {
g.text(position.x, position.y + idx * CharHeight, line)
}
}
private def recomputeProperties(): Unit = {
cachedText = text
cachedWrapWidth = wrapWidth
cachedLines = wrap(cachedText, cachedWrapWidth)
cachedWidth = getWidth(cachedLines)
}
}
object Text {
private val CharHeight = 16
private def getWidth(codepoint: Int): Int = FontUtils.wcwidth(codepoint)
private def getWidth(line: String): Int =
line.codePoints().map(getWidth).sum()
private def getWidth(lines: Iterable[String]): Int =
lines.iterator.map(getWidth).maxOption.getOrElse(0)
private def wrap(text: String, wrapWidth: Option[Int]): ArrayBuffer[String] = {
val lines = text.linesIterator
.flatMap(line => wrapWidth match {
case Some(wrapWidth) if getWidth(line) > wrapWidth => wrapLine(line, wrapWidth)
case _ => Some(line)
})
.to(ArrayBuffer)
val lastNonEmptyLineIdx = lines.lastIndexWhere(_.nonEmpty)
lines.takeInPlace(lastNonEmptyLineIdx + 1)
lines
}
private def wrapLine(line: String, wrapWidth: Int): Iterable[String] = {
// adapted from cheburator's message splitter
val lines = ArrayBuffer.empty[String]
var lineStart = 0
var pos = -1
var lineWidth = 0
var lastSpacePos = -1
var lastSpaceSize = 1
var spaceSeq = false
def firstLine: Boolean = lines.isEmpty
def pushLine(line: String): Unit = {
lines += line
lastSpacePos = -1
lastSpaceSize = 1
lineWidth = 0
spaceSeq = false
}
while (pos + 1 < line.length) {
pos += 1
val (c, count) = if (pos + 1 < line.length && Character.isSurrogatePair(line(pos), line(pos + 1))) {
(Character.toCodePoint(line(pos), line(pos + 1)), 2)
} else (line(pos): Int, 1)
val isSpace = Character.isSpaceChar(c)
if (isSpace && pos == lineStart && !firstLine) {
// skip leading space
lineStart += count
} else {
if (!isSpace) {
spaceSeq = false
}
if (isSpace && !spaceSeq) {
lastSpacePos = pos
lastSpaceSize = count
spaceSeq = true
}
lineWidth += getWidth(c)
if (lineWidth > wrapWidth) {
if (lastSpacePos >= (pos - lineStart) / 2) {
val newLine = line.substring(lineStart, lastSpacePos)
// `+ lastSpaceSize` starts the line after the last whitespace character
// we set pos to the same position -- but before it gets there, it'll get incremented by `count`,
// so we do the subtraction
lineStart = lastSpacePos + lastSpaceSize
pos = lastSpacePos + lastSpaceSize - count
pushLine(newLine)
} else {
val newLine = line.substring(lineStart, pos)
lineStart = pos
pos -= 1
pushLine(newLine)
}
}
}
// subtract one, which we'll add back at the start of the next iteration
pos += count - 1
}
if (lineStart != pos + 1) {
pushLine(line.substring(lineStart))
}
lines
}
}

View File

@ -0,0 +1,50 @@
package ocelot.desktop.ui.widget.card
import ocelot.desktop.geometry.{Padding2D, Size2D}
import ocelot.desktop.inventory.item.OcelotCardItem
import ocelot.desktop.ui.layout.{Layout, LinearLayout}
import ocelot.desktop.ui.widget.window.PanelWindow
import ocelot.desktop.ui.widget.{Button, Filler, LogWidget, PaddingBox, Widget}
import ocelot.desktop.util.Orientation
class OcelotCardWindow(item: OcelotCardItem) extends PanelWindow {
override protected def title: String = s"Ocelot card ${item.component.node.address}"
private val logWidget: LogWidget = new LogWidget {
override protected def messages: Iterable[String] = item.messages
override protected def textWidth: Int = 50
override def minimumSize: Size2D = super.minimumSize.copy(height = 300)
override def maximumSize: Size2D = minimumSize
}
setInner(new Widget {
override val layout: Layout = new LinearLayout(this, orientation = Orientation.Vertical)
children :+= logWidget
children :+= new PaddingBox(
new Widget {
children :+= new Filler
children :+= new Button {
override def text: String = "Clear"
override def onClick(): Unit = clear()
}
},
Padding2D(top = 4)
)
})
private def clear(): Unit = {
item.clear()
}
def onMessagesAdded(count: Int): Unit = {
logWidget.onMessagesAdded(count)
}
def onMessagesCleared(): Unit = {
logWidget.onMessagesCleared()
}
}