Compare commits

...

242 Commits

Author SHA1 Message Date
threeoh6000 e2518e734c Fix Arch documentation
pacman -Sy is a bad command and should never be ran as it syncs the repositories but doesn't actually  upgrade the software on the system which could royally screw up an unknowing Arch noob's system.
2022-08-27 15:45:54 +00:00
TheBrokenRail 35cafec1ee Tweaks 2022-08-10 17:21:38 -04:00
TheBrokenRail 4ab6b7aed1 New GCC Is *Still* Broken 2022-08-09 18:48:30 -04:00
TheBrokenRail edd346dd66 Stop Fighting CMake 2022-08-09 18:39:34 -04:00
TheBrokenRail 0d9f498aa7 Fix ZLib In "git status" 2022-08-07 14:14:00 -04:00
TheBrokenRail d761ad8614 Better CMake 2022-08-05 22:07:19 -04:00
TheBrokenRail 4977898bcd Use New Repos 2022-08-05 20:37:11 -04:00
TheBrokenRail 513628d91f More CMake Tweaks 2022-08-05 20:08:13 -04:00
TheBrokenRail 9a521ebca2 Remove Warnings From SDK 2022-08-03 13:08:20 -04:00
TheBrokenRail deae36ed94 Better SDK Setup 2022-08-01 19:56:35 -04:00
TheBrokenRail 00d6ee4f9a 2.4.3 2022-08-01 18:41:08 -04:00
TheBrokenRail 8dd562a20f Fix Signs With CP-437 2022-07-30 23:52:50 -04:00
TheBrokenRail c11c7203ef 2.4.2 2022-07-29 22:13:03 -04:00
TheBrokenRail 379da809cd 2.4.1 2022-07-20 02:58:14 -04:00
TheBrokenRail 96baf9627a Actually Fix Screen Rendering When GUI is Hidden 2022-07-16 00:02:51 -04:00
TheBrokenRail 279b101e46 Hotfix #2 2022-07-15 23:20:31 -04:00
TheBrokenRail b190851d36 Hotfix 2022-07-15 22:08:12 -04:00
TheBrokenRail c3c7d22006 Actually Fix CI 2022-07-15 20:09:51 -04:00
TheBrokenRail 3abbb0cb16 Improve Server Dockerfile 2022-07-15 19:54:58 -04:00
TheBrokenRail dda511f8ff Fix CI (Again) 2022-07-15 19:43:26 -04:00
TheBrokenRail 0ccc1ba6e8 Fix CI 2022-07-15 19:05:59 -04:00
TheBrokenRail 9d3a0964b0 Fix CI Stage Name 2022-07-15 17:54:43 -04:00
TheBrokenRail ed9bef8492 2.4.0 2022-07-15 17:27:21 -04:00
TheBrokenRail c4e26c5be2 Fix Classic HUD 2022-07-15 01:37:12 -04:00
TheBrokenRail 0c82db4116 Diable Broken Touchscreen-Specific Block Outline Behavior 2022-07-15 01:28:51 -04:00
TheBrokenRail ce168c1c16 Add Translucent Toolbar 2022-07-14 19:52:51 -04:00
TheBrokenRail 93eb7807aa Fix Attacking 2022-07-14 18:23:40 -04:00
TheBrokenRail 12074e15d9 Fix Sound 2022-07-14 18:11:44 -04:00
TheBrokenRail 010aaa89e3 Embed Feature Flag Data 2022-07-13 23:35:05 -04:00
TheBrokenRail 0e32fd36c8 Store Temporary Logs In Own Directory 2022-07-13 23:05:59 -04:00
TheBrokenRail 6c89e64f8b Add Classic HUD 2022-07-13 22:11:46 -04:00
TheBrokenRail 9fe6a2fb39 Remove Superfluous Mutexes 2022-07-13 19:32:08 -04:00
TheBrokenRail c87a6fa3c0 Improve Proxy Client 2022-07-13 17:02:18 -04:00
TheBrokenRail 69d3832815 Move Screenshot Code To ARM 2022-07-13 16:46:33 -04:00
TheBrokenRail 67002006f3 Vendor PatchELF 2022-07-13 11:58:35 -04:00
TheBrokenRail eb96d80e5a CMake Restructure 2022-07-11 23:51:27 -04:00
TheBrokenRail 968001897d Build Fixes + Don't Force EGL 2022-07-11 20:47:57 -04:00
TheBrokenRail 68519f06fd Add Buckets 2022-07-10 10:37:19 -04:00
TheBrokenRail b3b935dd1d Logging Changes 2022-07-08 22:40:56 -04:00
TheBrokenRail 006243d02f OpenAL Fixes 2022-07-08 15:00:01 -04:00
TheBrokenRail 3c1bce876c Run Benchmark During CI Test 2022-07-08 13:57:48 -04:00
TheBrokenRail 484d3e7f90 More Miscellaneous Fixes + Fixed GLES v1.1 Support 2022-07-08 00:25:01 -04:00
TheBrokenRail 23df63abb7 CMake Cleanup 2022-07-07 18:55:43 -04:00
TheBrokenRail 126c3d618d No More APT 2022-07-07 18:54:11 -04:00
TheBrokenRail 3937f88084 More Fixes 2022-07-07 00:37:53 -04:00
TheBrokenRail 4bd2fecfa2 Better package.sh 2022-07-04 16:51:56 -04:00
TheBrokenRail b539491713 Treat AppImages As Self-Mounting Tarballs 2022-07-04 16:44:00 -04:00
TheBrokenRail ea4c5c77a1 Cmake Refactor 2022-07-02 18:14:23 -04:00
TheBrokenRail e506dbb1bb GL Fixes 2022-06-30 19:53:32 -04:00
TheBrokenRail 699d83c61b Recipes API 2022-06-27 14:47:55 -04:00
TheBrokenRail 329f92c0a4 Fix Weird Shading 2022-06-26 22:01:31 -04:00
TheBrokenRail bfa0567ac9 Better Examples 2022-06-26 21:17:52 -04:00
TheBrokenRail a94708a1ae More Reliable Jenkins 2022-06-25 23:40:24 -04:00
TheBrokenRail 905a569c09 Better Flathub Badge 2022-06-25 23:38:29 -04:00
TheBrokenRail 53f602403a Cache Blacklist/Whitelist 2022-06-25 23:32:31 -04:00
TheBrokenRail 2f64552926 Fix SDK Bugs 2022-06-25 23:03:46 -04:00
TheBrokenRail 2b920f50ba Improve Example Mod README 2022-06-25 17:49:09 -04:00
TheBrokenRail d859a16b5a Initial SDK Support 2022-06-25 17:30:08 -04:00
TheBrokenRail 78e17d8c18 Block Running As Root 2022-06-24 20:37:52 -04:00
TheBrokenRail 0e7a108a0a Improve Build 2022-06-13 22:53:43 -04:00
TheBrokenRail ca21877000 Ditch FreeImage 2022-06-13 20:49:09 -04:00
TheBrokenRail f1ec29ec86 Build Tweak 2022-06-12 16:23:32 -04:00
TheBrokenRail 13ac816baa Fix Invalid AppStream XML 2022-06-10 23:49:15 -04:00
TheBrokenRail 6ba86b9193 Tiny Docker Fix 2022-06-10 22:02:43 -04:00
TheBrokenRail 49f8da2a80 Fix Build 2022-06-10 21:59:57 -04:00
TheBrokenRail e8faee62fa Improve AppStream 2022-06-09 23:23:37 -04:00
TheBrokenRail a8ff58f0c4 Update Dependency Installation 2022-06-09 23:10:29 -04:00
TheBrokenRail daccf65361 Improve Metadata 2022-06-09 21:31:40 -04:00
TheBrokenRail 3d508d7609 2.3.13 2022-06-05 16:14:03 -04:00
TheBrokenRail 0061edb3b2 2.3.12 2022-06-04 14:36:47 -04:00
TheBrokenRail baeeceeaac Slightly Faster 2022-06-04 14:34:15 -04:00
TheBrokenRail 211bf265ff Optimizations & Fixes 2022-06-03 22:25:22 -04:00
TheBrokenRail 0dd0706f52 2.3.11 2022-05-29 22:54:57 -04:00
TheBrokenRail 1743626113 Sweeping Media Layer Changes (GL ES 2.0 Support) 2022-05-29 18:44:27 -04:00
TheBrokenRail 4ed11b67e7 Add Front-Facing View 2022-05-17 18:31:25 -04:00
TheBrokenRail 365e238c29 Small Fix 2022-05-16 18:56:19 -04:00
TheBrokenRail 36c4ed7e4d Fix Stupid Mistake 2022-05-15 15:16:45 -04:00
TheBrokenRail cf1faf4835 Better Exit Code Messages 2022-05-15 13:51:28 -04:00
TheBrokenRail cb4560a602 Don't Require MCPI_DEBUG For Command Errors 2022-05-15 00:53:46 -04:00
TheBrokenRail b3a96dc3e2 2.3.10 2022-05-14 00:16:25 -04:00
TheBrokenRail be300a2809 Fix Zenity On Wayland 2022-05-13 23:27:06 -04:00
TheBrokenRail 77d7b82a14 Add Crash Report Dialog 2022-05-13 22:36:12 -04:00
TheBrokenRail b59c580f6a Fix Build On Ubuntu 22.04 & Bug Fixes 2022-05-11 18:24:03 -04:00
TheBrokenRail 524a390921 Use Debian Sid As AppImage And ARMHF Sysroot Base 2022-05-04 20:47:15 -04:00
TheBrokenRail ead7e575f3 Allow Specifying Custom Sysroot 2022-05-03 21:08:56 -04:00
TheBrokenRail f2a9b274d2 Cleanup Sysroot Sources 2022-05-03 17:29:10 -04:00
TheBrokenRail dd4972172d Fix In-Source Build 2022-05-03 17:27:52 -04:00
TheBrokenRail 8822a22987 Re-Run CMake On Version Change 2022-05-02 22:52:52 -04:00
TheBrokenRail 53cb68beee 2.3.9 2022-05-02 22:46:53 -04:00
TheBrokenRail 47ae13ac51 Bundle An ARM Sysroot 2022-05-02 22:44:10 -04:00
TheBrokenRail 492725ed63 Colored Logs 2022-05-02 20:43:52 -04:00
TheBrokenRail 7c2d0d5625 2.3.8: Switch Up Mod Loading Order 2022-05-01 00:25:29 -04:00
TheBrokenRail 9449cdf747 Fix Bad Comment 2022-04-30 23:29:29 -04:00
TheBrokenRail d95a9e1871 Update Changelog Formatting 2022-04-30 22:34:52 -04:00
TheBrokenRail 8a83702c3c 2.3.7 2022-04-28 20:54:00 -04:00
TheBrokenRail be7e44fd3c Update GLFW 2022-04-28 17:00:11 -04:00
TheBrokenRail 651c49980e 2.3.6 2022-04-27 23:43:13 -04:00
TheBrokenRail 46a53ba3cf New Create World Dialog 2022-04-27 23:38:30 -04:00
TheBrokenRail 186728ca5f Small Tweaks 2022-04-24 22:30:35 -04:00
TheBrokenRail 9412c07c45 Fix ARM Check 2022-04-24 18:56:21 -04:00
TheBrokenRail 2717e062b3 Replace LINK_FLAGS With LINK_OPTIONS 2022-04-24 17:56:21 -04:00
TheBrokenRail 0723fb1894 Improve Docs 2022-04-23 23:01:52 -04:00
TheBrokenRail 16f919d147 2.3.5 2022-04-23 21:19:53 -04:00
TheBrokenRail e18fc9fc63 Simplify 2022-04-23 21:10:44 -04:00
TheBrokenRail 3ebdffd396 Fixes 2022-04-23 18:49:08 -04:00
TheBrokenRail 82b6252927 Classic UI By Default! 2022-04-23 16:46:40 -04:00
TheBrokenRail 4a35935daf Add Improved Title Background 2022-04-22 19:38:15 -04:00
TheBrokenRail 89c29f14b1 More AppImage Fixes 2022-04-20 18:21:29 -04:00
TheBrokenRail 4edfaeead4 More Fixes 2022-04-16 16:38:09 -04:00
TheBrokenRail bfcdd3c7e9 AppImage Fixes 2022-04-14 21:12:42 -04:00
TheBrokenRail 5467b5178f Fix LD_PRELOAD 2022-04-13 20:59:47 -04:00
TheBrokenRail 8f49c550ba 2.3.4 2022-04-12 22:08:27 -04:00
TheBrokenRail 50eb4801a0 Revert Earlier Username Decision 2022-04-12 20:38:44 -04:00
TheBrokenRail a3eef9fc3b Add "Fix Pause Menu" 2022-04-11 22:52:38 -04:00
TheBrokenRail f455780833 Add "Force Touch Inventory" 2022-04-11 19:59:21 -04:00
TheBrokenRail 0150879d2b Fix Options Button On Classic UI 2022-04-11 18:48:43 -04:00
TheBrokenRail 623cf06516 Fix Options Screen 2022-04-10 22:41:47 -04:00
TheBrokenRail 0b1849a9ad Make Death Messages Customizable Server-Side 2022-04-09 20:06:44 -04:00
TheBrokenRail 157d51e6b6 Improve feature_has 2022-04-09 20:01:16 -04:00
TheBrokenRail ed58356dd8 Fix Q Behavior 2022-04-02 19:25:03 -04:00
TheBrokenRail fae728061a Update Screenshot 2022-03-28 17:29:28 -04:00
TheBrokenRail 353565ce5a Hide Server Desktop Entry 2022-03-27 23:24:42 -04:00
TheBrokenRail efa21bc8a5 Fix AppStream 2022-03-27 16:42:24 -04:00
TheBrokenRail 61f9a329ea 2.3.3 2022-03-27 16:21:58 -04:00
TheBrokenRail 3c0c260920 Add Smooth Stone Slab 2022-03-25 22:40:13 -04:00
TheBrokenRail 0592db9bdf 2.3.2 2022-03-25 21:20:34 -04:00
TheBrokenRail 3fee57ce60 Fix Missing Comment 2022-03-25 21:09:29 -04:00
TheBrokenRail b3c32b211b Add Grass To Expanded Creative Inventory 2022-03-25 21:07:28 -04:00
TheBrokenRail ea92e5188e Add Nether Reactor Stages To Expanded Creative Inventory 2022-03-25 00:35:06 -04:00
TheBrokenRail 9a4b70b5ca Improve Temporary File Improving 2022-03-24 23:03:59 -04:00
TheBrokenRail b5974f3f46 Simplify Launch Process 2022-03-24 22:47:34 -04:00
TheBrokenRail 709de17558 Fix Nether Reactor With Creative Restrictions Disabled 2022-03-23 19:26:49 -04:00
TheBrokenRail 3894e98a04 2022! 2022-03-18 23:56:27 -04:00
TheBrokenRail bf890d190b Sort Feature Flags 2022-03-16 19:51:45 -04:00
TheBrokenRail a40da62b70 Speedup run_command 2022-03-16 19:51:33 -04:00
TheBrokenRail 59b8fd9f54 Make iterate_text_sections MCPI-Agnostic 2022-03-16 19:50:46 -04:00
TheBrokenRail 55a815643b Add "Disable V-Sync" Feature Flag 2022-03-16 19:49:13 -04:00
TheBrokenRail aa471fb4ba Update Zenity 2022-03-16 19:48:37 -04:00
TheBrokenRail 4c33b6da9a 2.3.1 Final 2022-03-14 21:51:38 -04:00
TheBrokenRail 3048b3bf50 Load Custom Mods First 2022-03-14 20:49:56 -04:00
TheBrokenRail 03312f44b6 2.3.1 2022-03-14 19:09:25 -04:00
TheBrokenRail bdeb45eed2 Hardcode ldconfig Path 2022-03-13 17:13:50 -04:00
TheBrokenRail 9f63fa712f Fix ARM32 Support 2022-03-12 22:52:58 -05:00
TheBrokenRail e319d46ea0 Update Changelog 2022-03-11 23:19:24 -05:00
TheBrokenRail c88cbd151e Shallow Submodules Just Break Things 2022-03-11 21:38:46 -05:00
TheBrokenRail 46abc4c4bd Fix Jenkins 2022-03-11 20:39:00 -05:00
TheBrokenRail 00f8ed4752 2.3.0 2022-03-11 20:34:50 -05:00
TheBrokenRail 0fd8ba7de9 Improve AppImages & Safer OpenAL 2022-03-11 20:02:38 -05:00
TheBrokenRail 07baea7b5a Vendor Zenity For AppImages 2022-03-11 00:00:13 -05:00
TheBrokenRail 8792e5749d Remove Broken WebKit Exclusion 2022-03-10 21:05:33 -05:00
TheBrokenRail 53b2c20b8b Fix More AppImage Bugs 2022-03-09 23:29:37 -05:00
TheBrokenRail 244a69d1aa Move CI Dockerfile 2022-03-09 22:54:30 -05:00
TheBrokenRail a1f777f632 Add MCPI_DEBUG & Improve Documentation 2022-03-09 22:40:21 -05:00
TheBrokenRail 5d8a1e4230 Small Debug Fixes 2022-03-09 22:08:47 -05:00
TheBrokenRail 742ead51e1 Vendor GLFW 2022-03-09 21:23:41 -05:00
TheBrokenRail c33a27b2ea AppImage! 2022-03-09 18:47:31 -05:00
TheBrokenRail c1377d4f2a Add "Disable Hosting LAN Worlds" 2022-03-07 17:03:03 -05:00
TheBrokenRail e0ebc7fc32 Fix Furnace Not Checking Item Auxiliary 2022-03-06 22:43:42 -05:00
TheBrokenRail 0fcda17120 (Hopefully) Improve CI Speed 2022-03-06 20:46:18 -05:00
TheBrokenRail e9e9b90bdb Use Ninja 2022-03-06 20:13:41 -05:00
TheBrokenRail 0fd562af40 Allow Disabling Raw Mouse Motion 2022-03-06 20:07:49 -05:00
TheBrokenRail 1eb06b6b60 Add Back ~/.minecraft-pi/mods & Fix Segmentation Fault With Media Layer Proxy 2022-03-06 18:22:28 -05:00
TheBrokenRail c6983ac6c5 Improve Build System + Use GCC (Clang Is Just Too Broken) 2022-03-06 15:53:27 -05:00
TheBrokenRail 4a69d38e35 Add "Close Current Screen On Death" 2022-01-02 15:26:56 -05:00
TheBrokenRail 5636abc051 Fix More Furnace UI 2022-01-01 19:04:58 -05:00
TheBrokenRail 33c7d025a5 2.2.10 2021-12-29 21:12:49 -05:00
TheBrokenRail 7f7bc08201 Update Image 2021-12-22 14:05:05 -05:00
TheBrokenRail b36df1d8ff Improve Handling When MCPI-Reborn Directory != MCPI Directory 2021-12-19 18:24:59 -05:00
TheBrokenRail bf58129164 Extended ASCII Is A Myth Perpetuated By ASCII Table Manufacturers 2021-12-19 17:17:34 -05:00
TheBrokenRail 654c719187 Add MCPI_OPEN_SOURCE_ONLY Build Option 2021-12-19 16:09:16 -05:00
TheBrokenRail e1e2977c29 Move Icon To Incorrect Place That Everyone Checks 2021-12-18 16:51:40 -05:00
TheBrokenRail a85fc1f5fa Fix CI Build 2021-12-18 16:29:35 -05:00
TheBrokenRail e3a4cabf61 Stop Using Static QEMU 2021-12-17 21:04:05 -05:00
TheBrokenRail 4c3fefae89 Fix Symlink 2021-12-17 20:01:29 -05:00
TheBrokenRail 729eff232a Move Icon Again... 2021-12-17 19:37:52 -05:00
TheBrokenRail 560c040416 Fix Desktop File 2021-12-17 19:22:03 -05:00
TheBrokenRail ea49470450 No More /opt 2021-12-17 19:07:58 -05:00
TheBrokenRail 5a5fe4c731 Fix CMake 2021-12-17 18:19:23 -05:00
TheBrokenRail 406aa3f9a6 Stuff Learned From Legacy 2021-11-30 21:54:43 -05:00
TheBrokenRail 55679dd54c Fix Small Bug 2021-11-30 21:58:44 +00:00
TheBrokenRail dbee357ebc Fix More Size Data 2021-11-29 22:54:40 +00:00
TheBrokenRail bc461d39d5 Fix More Size Info 2021-11-28 23:02:34 +00:00
TheBrokenRail 21de7487bb Fix Size Data 2021-11-28 21:42:26 +00:00
TheBrokenRail 7ad36d0ce1 Finally Make Server STDIN Code Not Suck As Much 2021-11-20 23:09:25 -05:00
TheBrokenRail d17416421a Remove Useless Code 2021-11-15 20:14:11 -05:00
TheBrokenRail 154adea292 Add Eating To Removed Creative Restrictions 2021-11-14 17:28:20 -05:00
TheBrokenRail 291e560c8f Last Minute 2.2.8 Fix 2021-11-14 13:37:51 -05:00
TheBrokenRail 472f5d67a5 2.2.8 2021-11-13 23:29:48 -05:00
TheBrokenRail a79a601c59 Use -ffast-math 2021-11-12 17:12:37 -05:00
TheBrokenRail e85231bf69 Fix ARMHF Output Path 2021-11-12 05:04:11 +00:00
TheBrokenRail da0aef568d Fix CI Test 2021-11-11 22:52:47 -05:00
TheBrokenRail f8b7af1370 Fix CI Again 2021-11-11 22:27:10 -05:00
TheBrokenRail 6a7d881258 Fix CI 2021-11-11 21:37:29 -05:00
TheBrokenRail 2e9ee42d75 Fix ZLib Includes 2021-11-11 20:37:43 -05:00
TheBrokenRail 941572063e Revert To Binary Packaging 2021-11-11 20:12:16 -05:00
TheBrokenRail 43d27e8e11 Fix Build Dependencies 2021-11-10 22:52:33 -05:00
TheBrokenRail 7e3cfaa1a8 Update Build Dependencies 2021-11-10 22:48:41 -05:00
TheBrokenRail 320e0c652a Add Missing File 2021-11-10 22:37:29 -05:00
TheBrokenRail e5fc2a61aa Revamp Packaging 2021-11-10 22:17:04 -05:00
TheBrokenRail 5cf4d7f915 Small Cleanup 2021-11-09 16:26:02 -05:00
TheBrokenRail 51d7974ded Fix Typo 2021-11-06 22:40:11 -04:00
TheBrokenRail 16ebea9ed6 Even More Symbols 2021-11-02 17:50:26 -04:00
TheBrokenRail 05587efc04 Fix CMake 2021-10-28 22:57:47 -04:00
TheBrokenRail 9ad6cc3906 Add Tile Symbols 2021-10-28 19:21:07 -04:00
TheBrokenRail 12de038f37 Improve Patch Comment 2021-10-27 18:14:30 -04:00
TheBrokenRail 1daede7dba Fix ARM Toolchain On Some Devices 2021-10-22 22:39:26 -04:00
TheBrokenRail 28a6d59c2d Fix Build Better 2021-10-22 18:36:09 -04:00
TheBrokenRail f2bd893241 Fix Build (Finally) 2021-10-22 17:28:26 -04:00
TheBrokenRail 28424aa86a Faster Build 2021-10-12 16:13:11 -04:00
TheBrokenRail 637f1c1132 2.2.7 2021-10-12 16:01:07 -04:00
TheBrokenRail 74d14ecaa6 Small Optimization 2021-10-07 16:54:47 -04:00
TheBrokenRail f3eaa57041 Fix Symbol Name 2021-10-04 19:46:51 -04:00
TheBrokenRail 015235b889 Clean Up 2021-10-04 19:42:55 -04:00
TheBrokenRail 8c356dd65c Update README Image 2021-09-30 20:28:37 -04:00
TheBrokenRail 6a9a22ac25 Fix Bug In Texture Scaling Code 2021-09-30 19:37:24 -04:00
TheBrokenRail c45211ad22 Improve Changelog Formatting 2021-09-28 16:03:56 -04:00
TheBrokenRail 7498c1e932 Scale Animated Textures 2021-09-28 14:04:05 -04:00
TheBrokenRail 734bded289 Add Note To Building Docs 2021-09-21 22:21:53 -04:00
TheBrokenRail b7b130e675 Fix Building Documentation 2021-09-21 22:15:04 -04:00
TheBrokenRail 0a65c91d14 Fix Cross-Compilation Toolchain (Again) 2021-09-20 23:16:09 -04:00
TheBrokenRail 55475a3a0c Fix Cross-Compilation Toolchain 2021-09-20 22:47:33 -04:00
TheBrokenRail f9acb08e4f Document Server Docker Image 2021-09-19 15:44:13 -04:00
TheBrokenRail db64afc550 Improve Build System 2021-09-16 22:00:40 -04:00
TheBrokenRail 0465dc75a7 Instead Of Crashing, Disable Polling Block Hits In Survival Mode Using The API 2021-09-16 16:39:24 -04:00
TheBrokenRail 68a252c3df Fix Crash When Taking Odd-Sized Screenshots 2021-09-15 19:12:03 -04:00
TheBrokenRail 866ebfe159 Don't Cache GCC Version 2021-09-14 19:29:48 -04:00
TheBrokenRail 1f3036c7e1 Improve Clang Toolchain (Again) 2021-09-14 19:04:39 -04:00
TheBrokenRail a338c11f9d Improve Clang Toolchain 2021-09-14 19:02:50 -04:00
TheBrokenRail 647a482fbd Build Using Clang 2021-09-14 18:39:23 -04:00
TheBrokenRail 6c791d6c9d Add More Missing Sound Events 2021-09-13 17:09:57 -04:00
TheBrokenRail d18afddf1b Prevent random.burp Sound From Crashing Game 2021-09-12 16:41:10 -04:00
TheBrokenRail d851a8f3e1 2.2.0 2021-09-12 00:08:01 -04:00
TheBrokenRail a762654e35 Split Headless And Server Mode Code 2021-08-26 23:05:26 -04:00
TheBrokenRail 4aeb2fd95b RIP Debian Buster, You Won't Be Missed 2021-08-26 20:33:01 -04:00
TheBrokenRail c60fb51fae Move ServerLevel To minecraft.h 2021-08-24 17:21:38 -04:00
TheBrokenRail 4597e824bb Split Off "Allow Joining Survival Servers" From Game-Mode Mod 2021-08-23 18:33:50 -04:00
TheBrokenRail d372169c79 Clean Up Some Code, No Noticeable Difference 2021-08-21 23:00:12 -04:00
TheBrokenRail 99b709fea7 Fix Crash On ARM Systems 2021-08-15 23:11:03 -04:00
TheBrokenRail 578bb1c89f Fix On 64-Bit ARM Systems 2021-08-05 21:00:41 -04:00
TheBrokenRail 80d5674781 Optimize Media Layer Proxy 2021-07-20 17:22:56 -04:00
TheBrokenRail a925463fdf Print Error Message If RakNet Fails To Start 2021-07-18 21:23:44 -04:00
TheBrokenRail a9830c3bba Fix RakNet::RakString Security Bug 2021-07-16 18:30:16 -04:00
218 changed files with 10786 additions and 3117 deletions

10
.gitignore vendored
View File

@ -1,6 +1,14 @@
/out
/debian/tmp
/.vscode
/build
/build*
/CMakeLists.txt.user
*.autosave
/AppImageBuilder.yml
/appimage-builder-cache
/appimage-build
/AppDir
/*.zsync
/*.AppImage
/core*
/qemu_*

16
.gitmodules vendored Normal file
View File

@ -0,0 +1,16 @@
[submodule "dependencies/libpng/src"]
path = dependencies/libpng/src
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/libpng.git
[submodule "dependencies/zlib/src"]
path = dependencies/libpng/zlib/src
url = https://github.com/madler/zlib.git
ignore = dirty
[submodule "dependencies/glfw/src"]
path = media-layer/core/dependencies/glfw/src
url = https://github.com/glfw/glfw.git
[submodule "dependencies/zenity/src"]
path = dependencies/zenity/src
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/zenity.git
[submodule "launcher/dependencies/patchelf/src"]
path = launcher/dependencies/patchelf/src
url = https://github.com/NixOS/patchelf.git

View File

@ -1,104 +1,175 @@
cmake_minimum_required(VERSION 3.13.0)
cmake_minimum_required(VERSION 3.16.0)
# Specify Options
option(MCPI_USE_MEDIA_LAYER_PROXY "Whether To Enable The Media Layer Proxy" FALSE)
option(MCPI_SERVER_MODE "Server Mode" FALSE)
set(MCPI_BUILD_MODE "both" CACHE STRING "\"arm\" = Build Only Code That Must Be ARM; \"native\" = Build Architecture-Independent Code; \"both\" = Build All Code As ARM")
set_property(CACHE MCPI_BUILD_MODE PROPERTY STRINGS "both" "arm" "native")
# Configure Build Mode
# Build Mode
set(MCPI_BUILD_MODE "native" CACHE STRING "\"arm\" = Build Only Code That Must Be ARM; \"native\" = Build Architecture-Independent Code")
set_property(CACHE MCPI_BUILD_MODE PROPERTY STRINGS "arm" "native")
if(MCPI_BUILD_MODE STREQUAL "arm")
set(USE_ARM32_TOOLCHAIN TRUE)
set(BUILD_ARM_COMPONENTS TRUE)
set(BUILD_NATIVE_COMPONENTS FALSE)
elseif(MCPI_BUILD_MODE STREQUAL "native")
set(USE_ARM32_TOOLCHAIN FALSE)
set(BUILD_ARM_COMPONENTS FALSE)
set(BUILD_NATIVE_COMPONENTS TRUE)
elseif(MCPI_BUILD_MODE STREQUAL "both")
set(USE_ARM32_TOOLCHAIN TRUE)
set(BUILD_ARM_COMPONENTS TRUE)
set(BUILD_NATIVE_COMPONENTS TRUE)
else()
message(FATAL_ERROR "Invalid Mode")
endif()
# Use Clang By Default
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
if(NOT DEFINED CMAKE_C_COMPILER)
set(CMAKE_C_COMPILER clang)
endif()
if(NOT DEFINED CMAKE_CXX_COMPILER)
set(CMAKE_CXX_COMPILER clang++)
endif()
# Specify Options
option(MCPI_IS_MIXED_BUILD "Whether The Architecture-Independent And ARM Code Are Different Architecture" FALSE)
option(MCPI_OPEN_SOURCE_ONLY "Only Install Open-Source Code (Will Result In Broken Install)" FALSE)
option(MCPI_IS_APPIMAGE_BUILD "AppImage Build" FALSE)
# Server/Headless Builds
option(MCPI_SERVER_MODE "Server Mode" FALSE)
option(MCPI_HEADLESS_MODE "Headless Mode" ${MCPI_SERVER_MODE})
# Media Layer
if(MCPI_HEADLESS_MODE)
set(DEFAULT_USE_MEDIA_LAYER_PROXY FALSE)
else()
set(DEFAULT_USE_MEDIA_LAYER_PROXY ${MCPI_IS_MIXED_BUILD})
endif()
option(MCPI_USE_MEDIA_LAYER_PROXY "Whether To Enable The Media Layer Proxy" ${DEFAULT_USE_MEDIA_LAYER_PROXY})
if(NOT MCPI_HEADLESS_MODE)
option(MCPI_USE_GLES1_COMPATIBILITY_LAYER "Whether To Enable The GLESv1_CM Compatibility Layer" TRUE)
endif()
# Setup ARM Cross Compilation
if(USE_ARM32_TOOLCHAIN)
include(cmake/arm-toolchain.cmake)
# App ID
set(DEFAULT_APP_ID "com.thebrokenrail.MCPIReborn")
if(MCPI_SERVER_MODE)
string(APPEND DEFAULT_APP_ID "Server")
else()
string(APPEND DEFAULT_APP_ID "Client")
endif()
set(MCPI_APP_ID "${DEFAULT_APP_ID}" CACHE STRING "App ID")
# Use LLD When Using Clang
if(CMAKE_C_COMPILER STREQUAL "clang")
add_link_options("-fuse-ld=lld")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld") # Fix try_compile()
# App Title
set(DEFAULT_APP_TITLE "Minecraft: Pi Edition: Reborn")
if(MCPI_SERVER_MODE)
string(APPEND DEFAULT_APP_TITLE " (Server)")
else()
string(APPEND DEFAULT_APP_TITLE " (Client)")
endif()
# Utility Functions
include(cmake/util.cmake)
set(MCPI_APP_TITLE "${DEFAULT_APP_TITLE}" CACHE STRING "App Title")
# Specify Variant Name
set(MCPI_VARIANT_NAME "minecraft-pi-reborn")
if(MCPI_SERVER_MODE)
set(MCPI_VARIANT_NAME "${MCPI_VARIANT_NAME}-server")
string(APPEND MCPI_VARIANT_NAME "-server")
else()
set(MCPI_VARIANT_NAME "${MCPI_VARIANT_NAME}-client")
string(APPEND MCPI_VARIANT_NAME "-client")
endif()
# Specify Installation Paths
set(MCPI_INSTALL_DIR "opt/${MCPI_VARIANT_NAME}")
set(MCPI_LIB_DIR "${MCPI_INSTALL_DIR}/lib")
set(MCPI_FALLBACK_LIB_DIR "${MCPI_INSTALL_DIR}/fallback-lib")
set(MCPI_INSTALL_DIR "lib/${MCPI_VARIANT_NAME}")
set(MCPI_BIN_DIR "${MCPI_INSTALL_DIR}/bin")
set(MCPI_LEGAL_DIR "${MCPI_INSTALL_DIR}/legal") # For Software Licenses
set(MCPI_SDK_DIR "${MCPI_INSTALL_DIR}/sdk")
set(MCPI_SDK_LIB_DIR "${MCPI_SDK_DIR}/lib")
set(MCPI_SDK_INCLUDE_DIR "${MCPI_SDK_DIR}/include")
# Optimizations
# Library Directory
set(MCPI_LIB_DIR "${MCPI_INSTALL_DIR}/lib")
if(BUILD_ARM_COMPONENTS)
string(APPEND MCPI_LIB_DIR "/arm")
elseif(BUILD_NATIVE_COMPONENTS)
string(APPEND MCPI_LIB_DIR "/native")
endif()
# Share Directory
set(MCPI_SHARE_DIR "share")
if(MCPI_IS_APPIMAGE_BUILD)
string(PREPEND MCPI_SHARE_DIR "usr/")
endif()
# Build Mode
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Release")
add_compile_options(-O3)
else()
add_compile_options(-g)
add_definitions(-DDEBUG)
# Prebuilt ARMHF Toolchain
option(MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN "Whether To Use A Prebuilt ARMHF Toolchain For Building ARM Components" ${MCPI_IS_MIXED_BUILD})
if(BUILD_ARM_COMPONENTS AND MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN)
include(cmake/prebuilt-armhf-toolchain.cmake)
endif()
# Start Project
project(minecraft-pi-reborn)
# Specify Default Installation Prefix
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "/" CACHE PATH "" FORCE)
# Utility Functions
include(cmake/util.cmake)
# Sanity Checks
set(IS_ARM_TARGETING FALSE)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l")
set(IS_ARM_TARGETING TRUE)
endif()
if(BUILD_NATIVE_COMPONENTS AND NOT IS_ARM_TARGETING AND NOT MCPI_IS_MIXED_BUILD)
message(FATAL_ERROR "Project is configured as a mixed-buld, but MCPI_IS_MIXED_BUILD is disabled.")
endif()
if(BUILD_ARM_COMPONENTS AND NOT IS_ARM_TARGETING)
message(FATAL_ERROR "ARM-Targeting Compiler Required")
endif()
# Buld LibPNG + ZLib + Download Minecraft: Pi Edition
if(BUILD_ARM_COMPONENTS)
add_subdirectory(dependencies)
# Specify Default Installation Prefix
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(DEFAULT_PREFIX "/usr")
if(MCPI_IS_APPIMAGE_BUILD)
set(DEFAULT_PREFIX "/")
endif()
set(CMAKE_INSTALL_PREFIX "${DEFAULT_PREFIX}" CACHE PATH "" FORCE)
endif()
# Required Compile Flags
string(CONCAT COMPILE_FLAGS_SETUP
# Optimizations
"if(CMAKE_BUILD_TYPE STREQUAL \"Release\")\n"
" add_compile_options(-O3 -s)\n"
"else()\n"
" add_compile_options(-g)\n"
"endif()\n"
# PIC
"set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)\n"
# Warnings
"add_link_options(-Wl,--no-undefined)\n"
# C Standard
"add_definitions(-D_GNU_SOURCE)\n"
"set(CMAKE_C_STANDARD 99)\n"
"set(CMAKE_CXX_STANDARD 11)\n"
# Skip RPath
"set(CMAKE_SKIP_BUILD_RPATH TRUE)"
)
cmake_language(EVAL CODE "${COMPILE_FLAGS_SETUP}")
# Fast Math
add_compile_options(-ffast-math)
# Warnings
add_compile_options(-Wall -Wextra -Werror -Wpointer-arith -Wshadow -Wnull-dereference)
add_link_options(-Wl,--no-undefined)
add_definitions(-D_GNU_SOURCE)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 11)
# Specify Constants
if(MCPI_SERVER_MODE)
add_definitions(-DMCPI_SERVER_MODE)
if(CMAKE_C_COMPILER_ID STREQUAL \"GNU\")
# Prevents False Positives
if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 10.0)
add_compile_options(-Wno-stringop-overflow)
endif()
if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 11.0)
add_compile_options(-Wno-array-bounds -Wno-stringop-overread)
endif()
endif()
# Buld Dependencies
add_subdirectory(dependencies)
# Version
file(STRINGS VERSION VERSION)
add_definitions(-DVERSION="${VERSION}")
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS VERSION
)
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" MCPI_VERSION)
file(TIMESTAMP "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" MCPI_VERSION_DATE "%Y-%m-%d" UTC)
# Build libreborn
add_subdirectory(libreborn)
@ -111,7 +182,31 @@ if(BUILD_NATIVE_COMPONENTS)
add_subdirectory(launcher)
endif()
# Include Symbols
if(BUILD_ARM_COMPONENTS)
add_subdirectory(symbols)
endif()
# Build Mods
if(BUILD_ARM_COMPONENTS)
add_subdirectory(mods)
endif()
# Include Images
if(BUILD_NATIVE_COMPONENTS)
add_subdirectory(images)
endif()
# Install SDK
if(BUILD_ARM_COMPONENTS)
install(EXPORT sdk DESTINATION "${MCPI_SDK_DIR}" FILE "sdk-targets.cmake" EXPORT_LINK_INTERFACE_LIBRARIES)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/sdk.cmake"
# Compile Flags
"${COMPILE_FLAGS_SETUP}\n"
# Log
"message(STATUS \"Using Reborn SDK v${MCPI_VERSION}\")\n"
# Include Targets
"include(\"\${CMAKE_CURRENT_LIST_DIR}/sdk-targets.cmake\")\n"
)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sdk.cmake" DESTINATION "${MCPI_SDK_DIR}")
endif()

View File

@ -1,21 +1,19 @@
FROM debian:bullseye
# Copy DEB
ADD ./out/minecraft-pi-reborn-server_*~bullseye_amd64.deb /root
FROM debian:bullseye-slim
# Install
RUN \
apt-get update && \
apt-get install -y tini && \
(dpkg -i /root/*.deb || :) && \
apt-get install -y tini qemu-user && \
apt-get --fix-broken install -y && \
rm -f /root/*.deb && \
rm -rf /var/lib/apt/lists/*
# Copy
ADD ./out/server-amd64 /app
# Setup Working Directory
RUN mkdir /data
WORKDIR /data
# Setup Entrypoint
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["minecraft-pi-reborn-server"]
CMD ["/app/usr/bin/minecraft-pi-reborn-server"]

31
Jenkinsfile vendored
View File

@ -1,11 +1,11 @@
pipeline {
agent none
stages {
stage('Debian Bullseye') {
stage('Debian Buster') {
agent {
docker {
image 'debian:bullseye'
args '-v /var/run/docker.sock:/var/run/docker.sock'
dockerfile {
filename 'scripts/ci/Dockerfile'
args '-v /var/run/docker.sock:/var/run/docker.sock --network host'
}
}
stages {
@ -15,13 +15,15 @@ pipeline {
}
post {
success {
archiveArtifacts artifacts: 'out/*.deb', fingerprint: true
archiveArtifacts artifacts: 'out/*.AppImage*', fingerprint: true
}
}
}
stage('Publish') {
steps {
sh 'apt-get update && apt-get install -y docker.io'
sh 'rm -rf ./out/server-amd64'
sh './scripts/build.sh server amd64'
sh 'docker build --no-cache --tag thebrokenrail/minecraft-pi-reborn-server .'
withCredentials([usernamePassword(credentialsId: 'docker_hub_login', usernameVariable: 'DOCKER_HUB_USERNAME', passwordVariable: 'DOCKER_HUB_PASSWORD')]) {
sh 'docker login -u "${DOCKER_HUB_USERNAME}" -p "${DOCKER_HUB_PASSWORD}"'
@ -31,24 +33,5 @@ pipeline {
}
}
}
stage('Debian Buster') {
agent {
docker {
image 'debian:buster'
}
}
stages {
stage('Build') {
steps {
sh './scripts/ci/run.sh'
}
post {
success {
archiveArtifacts artifacts: 'out/*.deb', fingerprint: true
}
}
}
}
}
}
}

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 TheBrokenRail
Copyright (c) 2022 TheBrokenRail
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1 +1 @@
2.1.3
2.4.3

View File

@ -1,13 +0,0 @@
# Compile For ARM
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64_be" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "armv8b" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "armv8l")
# Force 32-Bit Compile
add_compile_options("-m32")
elseif(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "arm")
# Use ARM Cross-Compiler
set(TARGET "arm-linux-gnueabihf")
set(CMAKE_C_COMPILER "${TARGET}-gcc")
set(CMAKE_CXX_COMPILER "${TARGET}-g++")
set(CMAKE_FIND_ROOT_PATH "/usr/${TARGET}" "/usr/lib/${TARGET}")
endif()
set(CMAKE_SYSTEM_NAME "Linux")
set(CMAKE_SYSTEM_PROCESSOR "arm")

View File

@ -1,10 +0,0 @@
# Compile For ARM64
if(NOT (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64_be" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "armv8b" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "armv8l"))
# Use ARM64 Cross-Compiler
set(TARGET "aarch64-linux-gnu")
set(CMAKE_C_COMPILER "${TARGET}-gcc")
set(CMAKE_CXX_COMPILER "${TARGET}-g++")
set(CMAKE_FIND_ROOT_PATH "/usr/${TARGET}" "/usr/lib/${TARGET}")
endif()
set(CMAKE_SYSTEM_NAME "Linux")
set(CMAKE_SYSTEM_PROCESSOR "aarch64")

View File

@ -0,0 +1,12 @@
# Read Hex Data
file(READ "${EMBED_IN}" data HEX)
# Convert Hex Data For C Compatibility
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," data "${data}")
# Get C Name
get_filename_component(name "${EMBED_IN}" NAME)
string(MAKE_C_IDENTIFIER "${name}" name)
# Write Data
file(WRITE "${EMBED_OUT}" "#include <stddef.h>\nconst unsigned char ${name}[] = {${data}};\nconst size_t ${name}_len = sizeof (${name});\n")

View File

@ -0,0 +1,77 @@
# Pick URL
execute_process(COMMAND uname -m OUTPUT_VARIABLE arch OUTPUT_STRIP_TRAILING_WHITESPACE)
if(arch STREQUAL "x86_64")
set(toolchain_url "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz")
set(toolchain_sha256 "aa074fa8371a4f73fecbd16bd62c8b1945f23289e26414794f130d6ccdf8e39c")
elseif(arch STREQUAL "aarch64" OR arch STREQUAL "armv8b" OR arch STREQUAL "armv8l")
set(toolchain_url "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-aarch64-arm-none-linux-gnueabihf.tar.xz")
set(toolchain_sha256 "fccd7af76988da2b077f939eb2a78baa9935810918d2bf3f837bc74f52efa825")
else()
message(FATAL_ERROR "Unable To Download Prebuilt ARMHF Toolchain")
endif()
# Download If Needed
include(FetchContent)
set(FETCHCONTENT_QUIET FALSE)
FetchContent_Declare(
prebuilt-armhf-toolchain
URL "${toolchain_url}"
URL_HASH "SHA256=${toolchain_sha256}"
)
FetchContent_MakeAvailable(prebuilt-armhf-toolchain)
set(FETCHCONTENT_QUIET TRUE)
set(toolchain_dir "${prebuilt-armhf-toolchain_SOURCE_DIR}")
# Force Toolchain
file(WRITE "${toolchain_dir}/toolchain.cmake"
"set(CMAKE_C_COMPILER \"\${CMAKE_CURRENT_LIST_DIR}/bin/arm-none-linux-gnueabihf-gcc\")\n"
"set(CMAKE_CXX_COMPILER \"\${CMAKE_CURRENT_LIST_DIR}/bin/arm-none-linux-gnueabihf-g++\")\n"
"set(CMAKE_SYSTEM_NAME \"Linux\")\n"
"set(CMAKE_SYSTEM_PROCESSOR \"arm\")\n"
)
set(CMAKE_TOOLCHAIN_FILE "${toolchain_dir}/toolchain.cmake" CACHE STRING "" FORCE)
# Build Sysroot
set(sysroot_dir "${CMAKE_CURRENT_BINARY_DIR}/bundled-armhf-sysroot")
if("${toolchain_dir}/bin/arm-none-linux-gnueabihf-gcc" IS_NEWER_THAN "${sysroot_dir}")
# Create Directory
file(REMOVE_RECURSE "${sysroot_dir}")
file(MAKE_DIRECTORY "${sysroot_dir}")
# Copy Files From Toolchain
file(
COPY "${toolchain_dir}/arm-none-linux-gnueabihf/libc/"
DESTINATION "${sysroot_dir}"
USE_SOURCE_PERMISSIONS
FILES_MATCHING
PATTERN "*.so*"
)
# Delete Unneeded Files
file(REMOVE_RECURSE "${sysroot_dir}/usr/lib/audit")
# Strip Files
file(GLOB_RECURSE files LIST_DIRECTORIES FALSE "${sysroot_dir}/*")
foreach(file IN LISTS files)
execute_process(COMMAND "${toolchain_dir}/bin/arm-none-linux-gnueabihf-strip" "${file}" RESULT_VARIABLE ret)
# Check Result
if(NOT ret EQUAL 0)
# Delete Invalid Files
file(REMOVE "${file}")
endif()
endforeach()
# Setup gconv
file(
COPY "${toolchain_dir}/arm-none-linux-gnueabihf/libc/usr/lib/gconv/gconv-modules"
DESTINATION "${sysroot_dir}/usr/lib/gconv"
USE_SOURCE_PERMISSIONS
)
endif()
# Install Sysroot (Skipping Empty Directories)
file(GLOB_RECURSE files LIST_DIRECTORIES FALSE RELATIVE "${sysroot_dir}" "${sysroot_dir}/*")
foreach(file IN LISTS files)
get_filename_component(parent "${file}" DIRECTORY)
install(PROGRAMS "${sysroot_dir}/${file}" DESTINATION "${MCPI_INSTALL_DIR}/sysroot/${parent}")
endforeach()

View File

@ -0,0 +1,7 @@
# Compile For x86_64
include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake")
# Use x86_64 Cross-Compiler
setup_toolchain("x86_64-linux-gnu")
# Details
set(CMAKE_SYSTEM_NAME "Linux")
set(CMAKE_SYSTEM_PROCESSOR "x86_64")

View File

@ -0,0 +1,7 @@
# Compile For ARM64
include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake")
# Use ARM64 Cross-Compiler
setup_toolchain("aarch64-linux-gnu")
# Details
set(CMAKE_SYSTEM_NAME "Linux")
set(CMAKE_SYSTEM_PROCESSOR "aarch64")

View File

@ -0,0 +1,7 @@
# Compile For ARM
include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake")
# Use ARM Cross-Compiler
setup_toolchain("arm-linux-gnueabihf")
# Details
set(CMAKE_SYSTEM_NAME "Linux")
set(CMAKE_SYSTEM_PROCESSOR "arm")

View File

@ -0,0 +1,38 @@
# Setup Toolchain
macro(setup_toolchain target)
# Target Variants
set(target_variants "${target}")
macro(add_target_variant value)
string(REPLACE "-linux" "-${value}-linux" target_variant "${target}")
list(APPEND target_variants "${target_variant}")
endmacro()
add_target_variant(unknown)
add_target_variant(none)
add_target_variant(pc)
# Find Compiler
macro(find_compiler output name)
set(possible_names "")
foreach(possible_target IN LISTS target_variants)
list(APPEND possible_names "${possible_target}-${name}")
endforeach()
find_program(
"${output}"
NAMES ${possible_names}
NO_CACHE
)
if("${${output}}" STREQUAL "${output}-NOTFOUND")
message(FATAL_ERROR "Unable To Find ${name}")
endif()
endmacro()
find_compiler(CMAKE_C_COMPILER "gcc")
find_compiler(CMAKE_CXX_COMPILER "g++")
# Extra
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# Custom Search Paths
if(NOT DEFINED ENV{MCPI_TOOLCHAIN_USE_DEFAULT_SEARCH_PATHS})
# Find Root
set(CMAKE_FIND_ROOT_PATH "/usr/${target}" "/usr/lib/${target}" "/usr")
# pkg-config
set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/${target}/pkgconfig:/usr/${target}/lib/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig")
endif()
endmacro()

View File

@ -0,0 +1,9 @@
# Warning
message(WARNING "i686 Builds Are Unsupported, Proceed At Your Own Risk")
# Compile For i686
include("${CMAKE_CURRENT_LIST_DIR}/base-toolchain.cmake")
# Use i686 Cross-Compiler
setup_toolchain("i686-linux-gnu")
# Details
set(CMAKE_SYSTEM_NAME "Linux")
set(CMAKE_SYSTEM_PROCESSOR "i686")

View File

@ -1,20 +1,26 @@
# Symlink Function
function(install_symlink target link)
install(CODE "\
# Prepare\n \
set(file \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${link}\")\n \
\
# Create Directory\n \
get_filename_component(dir \"\${file}\" DIRECTORY)\n \
file(MAKE_DIRECTORY \${dir})\n \
\
# Create Symlink\n \
if(NOT EXISTS \"\${file}\")\n \
execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink ${target} \"\${file}\")\n \
message(\"-- Installing: \${file}\")\n \
else()\n \
message(\"-- Up-to-date: \${file}\")\n \
endif() \
")
get_filename_component(parent "${link}" DIRECTORY)
if(parent STREQUAL "")
set(parent ".")
endif()
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/symlink/${parent}")
file(CREATE_LINK "${target}" "${CMAKE_BINARY_DIR}/symlink/${link}" SYMBOLIC)
install(FILES "${CMAKE_BINARY_DIR}/symlink/${link}" DESTINATION "${parent}")
endfunction()
# Embed Resources
set(util_list_dir "${CMAKE_CURRENT_LIST_DIR}")
function(embed_resource target file)
# Get C Name
get_filename_component(name "${file}" NAME)
string(MAKE_C_IDENTIFIER "${name}" name)
# Add Command
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.c"
COMMAND "${CMAKE_COMMAND}"
ARGS "-DEMBED_IN=${CMAKE_CURRENT_SOURCE_DIR}/${file}" "-DEMBED_OUT=${CMAKE_CURRENT_BINARY_DIR}/${name}.c" "-P" "${util_list_dir}/embed-resource.cmake"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${file}" "${util_list_dir}/embed-resource.cmake"
)
# Add To Target
target_sources("${target}" PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/${name}.c")
endfunction()

7
debian/client-arm vendored
View File

@ -1,7 +0,0 @@
Package: minecraft-pi-reborn-client
Version: ${VERSION}
Maintainer: TheBrokenRail <connor24nolan@live.com>
Description: Fun with Blocks
Homepage: https://www.minecraft.net/en-us/edition/pi
Architecture: armhf
Depends: zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3

7
debian/client-arm64 vendored
View File

@ -1,7 +0,0 @@
Package: minecraft-pi-reborn-client
Version: ${VERSION}
Maintainer: TheBrokenRail <connor24nolan@live.com>
Description: Fun with Blocks
Homepage: https://www.minecraft.net/en-us/edition/pi
Architecture: arm64
Depends: zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libc6-armhf-cross, libstdc++6-armhf-cross

View File

@ -1,7 +0,0 @@
Package: minecraft-pi-reborn-client
Version: ${VERSION}
Maintainer: TheBrokenRail <connor24nolan@live.com>
Description: Fun with Blocks
Homepage: https://www.minecraft.net/en-us/edition/pi
Architecture: amd64
Depends: zenity, libgles1, libegl1, libglfw3 | libglfw3-wayland, libfreeimage3, libc6-armhf-cross, libstdc++6-armhf-cross, qemu-user-static

6
debian/server-arm vendored
View File

@ -1,6 +0,0 @@
Package: minecraft-pi-reborn-server
Version: ${VERSION}
Maintainer: TheBrokenRail <connor24nolan@live.com>
Description: Fun with Blocks
Homepage: https://www.minecraft.net/en-us/edition/pi
Architecture: armhf

7
debian/server-arm64 vendored
View File

@ -1,7 +0,0 @@
Package: minecraft-pi-reborn-server
Version: ${VERSION}
Maintainer: TheBrokenRail <connor24nolan@live.com>
Description: Fun with Blocks
Homepage: https://www.minecraft.net/en-us/edition/pi
Architecture: arm64
Depends: libc6-armhf-cross, libstdc++6-armhf-cross

View File

@ -1,7 +0,0 @@
Package: minecraft-pi-reborn-server
Version: ${VERSION}
Maintainer: TheBrokenRail <connor24nolan@live.com>
Description: Fun with Blocks
Homepage: https://www.minecraft.net/en-us/edition/pi
Architecture: amd64
Depends: libc6-armhf-cross, libstdc++6-armhf-cross, qemu-user-static

View File

@ -1,8 +1,14 @@
project(dependencies)
# ZLib
add_subdirectory(zlib)
# LibPNG
add_subdirectory(libpng)
if(BUILD_ARM_COMPONENTS)
add_subdirectory(libpng)
endif()
# Minecraft: Pi Edition
add_subdirectory(minecraft-pi)
if(BUILD_ARM_COMPONENTS AND NOT MCPI_OPEN_SOURCE_ONLY)
add_subdirectory(minecraft-pi)
endif()
# Zenity (Minimal Build)
if(BUILD_NATIVE_COMPONENTS AND NOT MCPI_SERVER_MODE)
add_subdirectory(zenity)
endif()

View File

@ -1,28 +1,33 @@
project(libpng)
include(FetchContent)
# ZLib (Needed By libpng)
add_subdirectory(zlib)
# Silence Warnings
add_compile_options(-w)
## LibPNG
# Download
set(SKIP_INSTALL_ALL TRUE) # Skip Default LibPNG Installation
FetchContent_Declare(
libpng
GIT_REPOSITORY "https://git.code.sf.net/p/libpng/code"
GIT_TAG "v1.2.59"
)
FetchContent_Populate(libpng)
set(ZLIB_LIBRARY zlib)
set(ZLIB_INCLUDE_DIR "${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}")
set(CMAKE_POLICY_DEFAULT_CMP0054 OLD) # Silence Warning
add_subdirectory("${libpng_SOURCE_DIR}" "${libpng_BINARY_DIR}")
set(CMAKE_POLICY_DEFAULT_CMP0054 NEW) # Re-Enable New Behavior
set_target_properties(png12 PROPERTIES LINK_FLAGS "-Wl,--version-script='${CMAKE_CURRENT_SOURCE_DIR}/libpng.vers'") # Use Symbol Versioning
set_target_properties(png12 PROPERTIES DEBUG_POSTFIX "") # Fix LibPNG Suffix In Debug Mode
# Options
set(PNG_TESTS FALSE CACHE BOOL "" FORCE)
set(PNG_NO_STDIO FALSE CACHE BOOL "" FORCE)
set(PNG_BUILD_ZLIB TRUE CACHE BOOL "" FORCE)
# Download
set(ZLIB_LIBRARY zlibstatic)
set(ZLIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/zlib/src" "${CMAKE_CURRENT_BINARY_DIR}/zlib/src")
add_subdirectory(src EXCLUDE_FROM_ALL)
# Use Symbol Versioning
set_target_properties(png12 PROPERTIES LINK_OPTIONS "LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libpng.vers")
# Ensure Build
add_custom_target(png12-build ALL DEPENDS png12)
# Install
install(TARGETS png12 DESTINATION "${MCPI_LIB_DIR}")
if(BUILD_ARM_COMPONENTS)
install(TARGETS png12 zlibstatic EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
endif()
# License
install(FILES src/LICENSE DESTINATION "${MCPI_LEGAL_DIR}/libpng")

1
dependencies/libpng/src vendored Submodule

@ -0,0 +1 @@
Subproject commit 6c445538879f9e916f8e62723d2ac7cd77d96191

16
dependencies/libpng/zlib/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,16 @@
project(zlib)
# Silence Warnings
add_compile_options(-w)
## zlib
# Download
set(CMAKE_POLICY_DEFAULT_CMP0022 NEW) # Fix Error
add_subdirectory(src EXCLUDE_FROM_ALL)
# Ensure Build
add_custom_target(zlib-build ALL DEPENDS zlibstatic)
# License
install(FILES src/README DESTINATION "${MCPI_LEGAL_DIR}/zlib")

1
dependencies/libpng/zlib/src vendored Submodule

@ -0,0 +1 @@
Subproject commit 21767c654d31d2dccdde4330529775c6c5fd5389

View File

@ -8,10 +8,14 @@ include(FetchContent)
FetchContent_Declare(
minecraft-pi
URL "${CMAKE_CURRENT_SOURCE_DIR}/minecraft-pi-0.1.1.tar.gz"
URL_HASH "SHA256=e0d68918874cdd403de1fd399380ae2930913fcefdbf60a3fbfebb62e2cfacab"
)
FetchContent_Populate(minecraft-pi)
# Install
install(DIRECTORY "${minecraft-pi_SOURCE_DIR}/" DESTINATION "${MCPI_INSTALL_DIR}" USE_SOURCE_PERMISSIONS)
install(
DIRECTORY "${minecraft-pi_SOURCE_DIR}/"
DESTINATION "${MCPI_INSTALL_DIR}/game"
USE_SOURCE_PERMISSIONS
REGEX "api" EXCLUDE
)
install_symlink("game/minecraft-pi" "${MCPI_INSTALL_DIR}/minecraft-pi")

18
dependencies/zenity/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,18 @@
project(zenity)
# Silence Warnings
add_compile_options(-w)
## Zenity
# Download
add_subdirectory(src EXCLUDE_FROM_ALL)
# Ensure Build
add_custom_target(zenity-build ALL DEPENDS zenity)
# Install
install(TARGETS zenity DESTINATION "${MCPI_BIN_DIR}")
# License
install(FILES src/COPYING DESTINATION "${MCPI_LEGAL_DIR}/zenity")

1
dependencies/zenity/src vendored Submodule

@ -0,0 +1 @@
Subproject commit 27cd9e88a72538b00d172dee67d94cb4ce6bc9b9

View File

@ -1,23 +0,0 @@
project(zlib)
include(FetchContent)
# Silence Warnings
add_compile_options(-w)
## zlib
# Download
set(SKIP_INSTALL_ALL TRUE) # Skip Default ZLib Installation
FetchContent_Declare(
zlib
GIT_REPOSITORY "https://github.com/madler/zlib.git"
GIT_TAG "v1.2.11"
)
FetchContent_Populate(zlib)
include_directories("${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}") # Fix ZLib Build
add_subdirectory("${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}")
# Install
install(TARGETS zlib DESTINATION "${MCPI_LIB_DIR}")

View File

@ -2,6 +2,11 @@
## Launch Sequence
### Common
1. The launcher forks itself
1. The child process continues the launch sequence.
2. The original process monitors the child process for crashes.
### Client
1. The launcher is started by the user
1. The launcher starts several Zenity dialogs to configure MCPI-Reborn
@ -34,11 +39,11 @@ The Media Layer handles MCPI's graphics calls and user input. It replaces MCPI's
This sub-component re-implements a subset of SDL 1.2 calls with GLFW. It also provides a few utility functions that are used internally by MCPI-Reborn.
The utility functions include:
* Taking Screenshots
* Fullscreen
* Audio
* Etc
This is always compiled for the host system's architecture.
This is always compiled for the host system's architecture unless the Media Layer Proxy is disabled.
This was created because SDL 1.2 has numerous bugs and is in-general unsupported.
@ -59,21 +64,13 @@ It is made of two parts:
While proxying all Media Layer Core API calls across UNIX pipes does hurt performance, it is better than emulating the entire graphics stack.
Using this in server-mode is redundant (and disallowed).
Using this in server-mode is redundant.
#### Extras
This sub-component contains code that must always be linked directly to MCPI.
This is always compiled for ARM.
#### Stubs
This sub-component implements stubs for various redundant libraries used by MCPI to silence linker errors.
This is always compiled for ARM.
##### What To Stub And What To Patch?
Most libraries (like ``bcm_host``) can just be replaced with stubs, because they don't need to do anything and aren't used by anything else. However, some libraries (like EGL and X11) might be used by some of MCPI-Reborn's dependencies (like GLFW) so instead of being replaced by a stub, each call is manually patched out from MCPI. A stub is still generated just in case that library isn't present on the system to silence linker errors, but it is only loaded if no other version is available.
#### Headers
This sub-component includes headers for SDL, GLES, and EGL allowing easy (cross-)compilation.
@ -87,19 +84,21 @@ This component contains various utility functions including:
* Code Patching (ARM Only)
* Logging
* MCPI Symbols
* Etc
The code patching is ARM only because it relies on hard-coded ARM instructions. However, this is irrelevant since code patching is only needed in ARM code (to patch MCPI).
### ``symbols``
This component contains all MCPI symbols.
## Dependencies
MCPI-Reborn has several dependencies:
* MCPI (Bundled)
* GLFW (Only In Client Mode)
* Open GL ES 1.1
* GLFW (Only In Client Mode; Bundled)
* Open GL ES 2.0
* EGL
* OpenAL (Only In Client Mode)
* ZLib (Required By LibPNG; Bundled)
* LibPNG (Bundled)
* FreeImage (Only In Client Mode)
* QEMU User Mode (Only On Non-ARM Hosts; Runtime Only)
* Zenity (Only In Client Mode; Runtime Only)
* Zenity (Only In Client Mode; Runtime Only; Bundled)

View File

@ -1,63 +1,22 @@
# Building
## Build Options
* ``MCPI_BUILD_MODE``
* ``arm``: Only Build ARM Components
* ``native``: Only Build Native Components
* ``both`` (Default): Build Both ARM And Native Components For ARM
* ``MCPI_SERVER_MODE``
* ``ON``: Enable Server Mode
* ``OFF`` (Default): Disable Server Mode
* ``MCPI_USE_MEDIA_LAYER_PROXY``
* ``ON``: Enable The Media Layer Proxy
* ``OFF`` (Default): Disable The Media Layer Proxy
## Build Dependencies
* Common
* ARM Compiler
* Host Compiler (Clang)
* CMake
* Host Architecture Dependencies
* Client Mode Only
* GLFW
* FreeImage
## Runtime Dependencies
* Non-ARM Host Architectures
* QEMU User-Mode Static
* Host Architecture Dependencies
* CLient Mode Only
* OpenGL ES 1.1
* GLFW
* FreeImage
* Zenity
## Two-Step Build
Use this when the host architecture is not ARM.
## Dependencies
### Debian/Ubuntu
```sh
# Create Build Directory
mkdir build && cd build
# Build ARM Components
mkdir arm && cd arm
cmake -DMCPI_BUILD_MODE=arm ../..
make -j$(nproc) && sudo make install
# Build Native Components
mkdir native && cd native
cmake -DMCPI_BUILD_MODE=native ../..
make -j$(nproc) && sudo make install
./scripts/install-dependencies.sh
```
## One-Step Build
Use this when the host architecture is ARM.
## Instructions
```sh
# Create Build Directory
mkdir build && cd build
# Build
cmake ..
make -j$(nproc) && sudo make install
./scripts/build.sh <client|server> <armhf|arm64|i686|amd64>
```
### Custom CMake Arguments
```sh
./scripts/setup.sh <client|server> <armhf|arm64|i686|amd64> <Custom CMake Arguments>
./scripts/build.sh <client|server> <armhf|arm64|i686|amd64>
```
### Environment Variables
* ``MCPI_TOOLCHAIN_USE_DEFAULT_SEARCH_PATHS``: Use Default CMake Search Paths Rather Than Guessing

View File

@ -1,5 +1,203 @@
# Changelog
**2.4.3**
* Fix Signs With CP-437
**2.4.2**
* Fix Picking Up Lava
* Fix Wayland App ID
**2.4.1**
* Allow More Characters In Usernames And Chat
* Fix Running On ARMHF Debian Buster
**2.4.0**
* [Modding SDK](../example-mods/README.md)
* Cache Blacklist/Whitelist
* More Reliable AppImages
* CMake Refactors
* Disable Broken Touchscreen-Specific Block Outline Behavior
* Add ``Remove Forced GUI Lag (Can Break Joining Servers)`` Feature Flag (Disabled By Default)
* Add ``Add Buckets`` Feature Flag (Enabled By Default)
* Add ``Classic HUD`` Feature Flag (Enabled By Default)
* Add ``Translucent Toolbar`` Feature Flag (Enabled By Default)
* Add ``Force EGL`` Feature Flag (Disabled By Default)
* Fix Sound Pitch/Volume/Attenuation
* Fix Holding Left-Click When Attacking
* Don't Force EGL (Should Fix Some NVIDIA Systems)
* Performance Fixes
**2.3.13**
* Fix Texture Bug
**2.3.12**
* Media Layer Proxy Optimizations
* Bug Fixes
**2.3.11**
* ``--version`` Command Line Option
* TPS Measured In Benchmark & Server
* Front-Facing Third-Person
* GLESv1 Comparability Layer
* Miscellaneous Bug Fixes
**2.3.10**
* Add Crash Report Dialog
* Disable V-Sync By Default
* Refactor Child Process Management
* Improve Build System
* Support For Building On Ubuntu 22.04
**2.3.9**
* Bundle An ARM Sysroot
* Not Used On ARM32 Systems
* Based On Debian Bullseye
* Colored Log Output
**2.3.8**
* Switch Up Mod Loading Order
**2.3.7**
* Don't Append Hyphens To New World Name, Only Folder Names
**2.3.6**
* Fix ``Invert Y-axis`` Option Name
* Improve Touch GUI Inventory In Non-Touch GUI
* New Create World Dialog
* Controlled By ``Implement Create World Dialog`` Feature Flag (Enabled By Default)
* Custom World Names
* Game-Mode Selection
* Custom Seeds
**2.3.5**
* Renamed Some Feature Flags
* Add ``Improved Title Background`` Feature Flag (Enabled By Default)
* Non-Touch GUI Rework
* Make ``Full Touch GUI`` Feature Flag Disabled By Default
* Add ``Force Touch GUI Button Behavior`` Feature Flag (Enabled By Default)
* Add ``Improved Button Hover Behavior`` Feature Flag (Enabled By Default)
**2.3.4**
* AppImage Fixes
* Make Death Messages Customizable Server-Side
* Fix Q-Key Behavior Behavior When Editing Signs
* Add ``Force Touch Inventory`` Feature Flag (Disabled By Default)
* Add ``Fix Pause Menu`` Feature Flag (Enabled By Default)
* Enables Server Visibility Toggle Button
* Options Changes (Not Supported On Legacy)
* Add ``Fix Options Screen`` Feature Flag (Enabled By Default)
* Adds Options Button To Classic UI Start Screen
* Removes Useless Options Toggles
* Fixes Options Toggles' Default Position
* Store Multiple Settings In `options.txt`
* ``Peaceful Mode`` Feature Flag Moved To ``game_difficulty``
* ``Smooth Lighting`` Feature Flag Moved To ``gfx_ao``
* ``Fancy Graphics`` Feature Flag Moved To ``gfx_fancygraphics``
* ``Disable Hosting LAN Worlds`` Feature Flag Moved To ``mp_server_visible_default``
**2.3.3**
* Add More Blocks To Expanded Creative Inventory
* Add AppStream Metadata
**2.3.2**
* Simplify Launch Sequence
* Add More Blocks To Expanded Creative Inventory
* Fix Nether Reactor With Creative Restrictions Disabled
* Alphabetize Feature Flags
* Add ``Disable V-Sync`` Feature Flag (Disabled By Default)
**2.3.1**
* Internal Refactor Of ``libreborn``
* Remove Use Of ``/bin/sh``
* Load Custom Mods First
* Use Zenity Dark Mode
* Add ``Improved Cursor Rendering`` Feature Flag (Enabled By Default)
**2.3.0**
* Switch To AppImage For Packaging
* Prevent OpenAL From Crashing When Out Of Memory
* Vendor GLFW & Zenity
* Seamless Wayland Support
* Add ``MCPI_DEBUG`` Environmental Variable
* Add ``Disable Hosting LAN Worlds`` Feature Flag (Disabled By Default)
* Add ``Fix Furnace Not Checking Item Auxiliary`` Feature Flag (Enabled By Default)
* Add ``Disable Raw Mouse Motion (Not Recommended)`` Feature Flag (Disabled By Default) For Broken X11 Setups
* Added Back `~/.minecraft-pi/mods`
* Improve Build System
* Improve Documentation
**2.2.11**
* Add ``Close Current Screen On Death`` Feature Flag (Enabled By Default) To Prevent Bugs
* Fix More Furnace UI Bugs When Using "Disable 'gui_blocks' Atlas"
**2.2.10**
* Fix Bug With Picking Up Items In "Remove Creative Mode Restrictions" Mode
**2.2.9**
* Fix String Sanitization
* Store Files In `/usr/lib`
**2.2.8**
* Add ``Hide Chat Messages`` Optional Feature Flag
* Add ``Remove Creative Mode Restrictions`` Optional Feature Flag
* Improve GLFW->SDL Mouse Motion Event Conversion
* Performance Optimizations
* Make Majority Of Server-Specific Logging Code Also Apply To The Client
* Simple Benchmark Mode
* Fix Typo When Audio Source File Doesn't Exist
* Improve Build System
**2.2.7**
* Fix Crash When OpenAL Is Unavailable
* Fix Command Input In Server
**2.2.5**
* Fix Bug In Texture Scaling Code
**2.2.5**
* Scale Animated Textures
* Add More Blocks To Expanded Creative Inventory
* Reduce Unnecessary Logging
* Log IPs In Server Mode
**2.2.4**
* Instead Of Crashing, Disable Polling Block Hits In Survival Mode Using The API
**2.2.3**
* Fix Crash When Taking Odd-Sized Screenshots
**2.2.2**
* Add More Missing Sound Events
* Make Missing Sound Event Cause Warning Rather Than Crash
**2.2.1**
* Prevent ``random.burp`` Sound From Crashing Game
* Always Cleanup Media Layer, Even On Crash
* Resolve All Sounds On Startup
**2.2.0**
* Sound Support
* Split Off ``Allow Joining Survival Servers`` From Game-Mode Mod
* Separate Headless Code From Server Code
* Fix Bug Where ``RakNetInstance`` Starts Pinging Potential Servers Before The "Join Game" Screen Is Opened
* Clean-Up Code
* Remove Support For Debian Buster
**2.1.8**
* Fix Crash On ARM Systems
**2.1.7**
* Fix On 64-Bit ARM Systems
**2.1.6**
* Optimize Media Layer Proxy
**2.1.5**
* Print Error Message If RakNet Fails To Start
**2.1.4**
* Fix ``RakNet::RakString`` Security Bug
**2.1.3**
* Workaround Broken Library Search Path On Some ARM 32-Bit Systems
@ -36,7 +234,7 @@
* Optimize Media Layer Proxy
**2.0.3**
* Make "kill" Admin Command Print Death Message
* Make ``kill`` Admin Command Print Death Message
**2.0.2**
* Fix Mouse Cursor Bugs

View File

@ -1,11 +1,45 @@
# Command Line Arguments
# Command Line Usage
## ``--print-available-feature-flags`` (Client Mode Only)
If you run MCPI-Reborn with ``--print-available-feature-flags``, it will print the available feature flags and then immediately exit. The feature flags are printed in the following format:
## Command Line Arguments
### ``--version`` (Or ``-v``)
If you run MCPI-Reborn with ``--version`` it will print its version to ``stdout``.
### ``--print-available-feature-flags`` (Client Mode Only)
If you run MCPI-Reborn with ``--print-available-feature-flags``, it will print the available feature flags to ``stdout`` and then immediately exit.
The feature flags are printed in the following format:
```
TRUE This Flag Is On By Default
FALSE This Flag Is Off By Default
```
## ``--only-generate`` (Server Mode Only)
### ``--default`` (Client Mode Only)
If you run MCPI-Reborn with ``--default``, it will skip the startup configuration dialogs and just use the default values.
### ``--only-generate`` (Server Mode Only)
If you run MCPI-Reborn with ``--only-generate``, it will immediately exit once world generation has completed. This is mainly used for automatically testing MCPI-Reborn.
### ``--benchmark`` (Client Mode Only)
If you run MCPI-Reborn with ``--benchmark``, it will enter a simple benchmark mode. This means automatically loading a newly generated world, then rotating the camera for a period of time. When it has finished, it will then exit and print the average FPS while the world was loaded. In this mode, all user input is blocked. However you can still modify rendering settings by changing feature flags.
The world used will always be re-created on start and uses a hard-coded seed.
## Environmental Variables
### ``MCPI_DEBUG``
This enables debug logging if it is set.
### Client Mode Only
If any of the following variables aren't set, one configuration dialog will open on startup for each unset variable.
#### ``MCPI_FEATURE_FLAGS``
This corresponds to ``--print-available-feature-flags``. This is just a list of all enabled feature flags separated by ``|``.
For instance, the string ``Feature A|Feature B`` would enable both ``Feature A`` and ``Feature B`` and *disable every other available feature flag*.
#### ``MCPI_RENDER_DISTANCE``
This is the render distance. The possible values are: ``Far``, ``Normal``, ``Short``, and ``Tiny``.
#### ``MCPI_USERNAME``
This is the username.

View File

@ -1,14 +1,19 @@
# Dedicated Server
The dedicated server is a version of Minecraft: Pi Edition modified to run in a headless environment. It loads settings from a ``server.properties`` file.
This server is also compatible with MCPE Alpha v0.6.1.
This server is also compatible with MCPE Alpha v0.6.1[^1].
## Setup
### Debian Package
To use, install and run ``minecraft-pi-reborn-server``. It will generate the world and ``server.properties`` in the current directory.
### Docker Image
An official Docker image is also provided: [thebrokenrail/minecraft-pi-reborn-server](https://hub.docker.com/r/thebrokenrail/minecraft-pi-reborn-server).
## Server Limitations
* Player data is not saved because of limitations with MCPE LAN worlds
* An easy workaround is to place your inventory in a chest before logging off
* Survival Mode servers are incompatible with unmodded MCPI
[^1]: The exception to this is buckets, those will crash MCPE players.

View File

@ -1,26 +1,27 @@
# Manual Installation
[Download Packages Here](https://jenkins.thebrokenrail.com/job/minecraft-pi-reborn/job/master/lastSuccessfulBuild/artifact/out/)
# Installation
## Picking A Package
## AppImage
Download packages [here](https://jenkins.thebrokenrail.com/job/minecraft-pi-reborn/job/master/lastSuccessfulBuild/artifact/out/).
### Name Format
```
minecraft-pi-reborn-<Variant>_X.Y.Z~<Distribution>_<Architecture>
```
### System Requirements
* Debian Buster/Ubuntu 18.04 Or Higher
* QEMU User-Mode
* Debian/Ubuntu: ``sudo apt install qemu-user``
* Arch: ``sudo pacman -S qemu-user``
* Client-Only Dependencies
* Graphics Drivers
* GTK+ 3
* Debian/Ubuntu: ``sudo apt install libgtk-3-0``
* Arch: ``sudo pacman -S gtk3``
* OpenAL
* Debian/Ubuntu: ``sudo apt install libopenal1``
* Arch: ``sudo pacman -S openal``
### Picking A Variant
* ``client``: Client mode, use this if you want to play MCPI
* ``server``: Server mode, use this if you want to host a dedicated MCPI server
### Running
Follow [these](https://docs.appimage.org/introduction/quickstart.html#how-to-run-an-appimage) instructions.
### Picking A Distribution
This specifies which version of Debian MCPI-Reborn was built against. Which one you should use depends on your current distribution. If your distribution supports it, you should use ``bullseye`` for better mouse sensitivity.
## Flatpak
<a href="https://flathub.org/apps/details/com.thebrokenrail.MCPIReborn"><img width="240" alt="Download On Flathub" src="https://flathub.org/assets/badges/flathub-badge-en.svg" /></a>
* Ubuntu 20.04+: ``bullseye``
* Raspberry Pi OS Buster: ``buster``
* Debian Bullseye+: ``bullseye``
* Debian Buster: ``buster``
### Picking An Architecture
* ``amd64``: x86_64, use this if you are using a device with an AMD or Intel processor
* ``armhf``: ARM 32-Bit, use this if you are using an ARM device (like a Raspberry Pi)
* ``arm64``: ARM 64-Bit, ``armhf`` but for 64-bit devices
### Note
Game data is stored in ``~/.var/app/com.thebrokenrail.MCPIReborn/.minecraft-pi`` instead of ``~/.minecraft-pi``.

View File

@ -1,5 +1,5 @@
# Documentation
* [View Manual Installation](INSTALL.md)
* [View Installation](INSTALL.md)
* [View Overriding Assets](OVERRIDING_ASSETS.md)
* [View Dedicated Server](DEDICATED_SERVER.md)
* [View Credits](CREDITS.md)
@ -8,4 +8,5 @@
* [View Architecture](ARCHITECTURE.md)
* [View Command Line Arguments](COMMAND_LINE.md)
* [View Multiplayer](MULTIPLAYER.md)
* [View Sound](SOUND.md)
* [View Changelog](CHANGELOG.md)

7
docs/SOUND.md Normal file
View File

@ -0,0 +1,7 @@
# Sound
One of MCPI-Reborn's main modifications is a sound-engine since MCPI doesn't include one by default[^1]. However, it can't be used out-of-box because MCPI doesn't contain any sound data and MCPI-Reborn can't include it because of copyright.
MCPE's sound data can be extracted from any MCPE v0.6.1[^2] APK file, just place its `libminecraftpe.so` into `~/.minecraft-pi/overrides` and you should have sound!
[^1]: The mute button is just leftover code from MCPE, it doesn't actually do anything in un-modded MCPI, however it is connected to MCPI-Reborn's sound-engine.
[^2]: This isn't a hard limit, an MCPE v0.8.1 APK would probably work, but don't rely on it.

View File

@ -2,6 +2,7 @@
| Name | Description |
| --- | --- |
| MCPI | Shorthand for Minecraft: Pi Edition |
| MCPE | Shorthand for Minecraft: Pocket Edition |
| Host Architecture | The native architecture of the CPU that MCPi-Reborn will be running on |
| Native Component | A component that *can* be compiled for the host architecture |
| ARM Component | A component that *must* be compiled for ARM |

19
example-mods/README.md Normal file
View File

@ -0,0 +1,19 @@
# Example Mods
This is an example of a mod that can be built using the modding SDK.
* **Expanded Creative Mod**: This specific mod adds even more items and blocks to the Creative Inventory. It was originally by [@Bigjango13](https://github.com/bigjango13).
* **Chat Commands Mod**: This specific mod makes an chat message starting with a ``/`` handled by the MCPI API.
* **Recipes Mod**: This specific mod demos custom recipes.
## The SDK
The modding SDK is a collection of exported CMake targets that allows anyone to create their own MCPI mod!
The SDK is copied to ``~/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake`` whenever MCPI-Reborn is started.
## How do I use this?
```sh
mkdir build
cd build
cmake ..
cp libexpanded-creative.so ~/.minecraft-pi/mods
```

15
example-mods/chat-commands/.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
/out
/debian/tmp
/.vscode
/build*
/CMakeLists.txt.user
*.autosave
/AppImageBuilder.yml
/appimage-builder-cache
/appimage-build
/AppDir
/*.zsync
/*.AppImage
/core*
/qemu_*
/cmake/.prebuilt-armhf-toolchain

View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.16.0)
# Build For ARM
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
# Start Project
project(chat-commands)
# Include SDK
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
# Build
add_library(chat-commands SHARED chat-commands.cpp)
target_link_libraries(chat-commands mods-headers reborn-patch symbols chat misc)

View File

@ -0,0 +1,25 @@
// Headers
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/chat/chat.h>
#include <mods/misc/misc.h>
// The Actual Mod
HOOK(chat_handle_packet_send, void, (unsigned char *minecraft, unsigned char *packet)) {
// Get Message
char *message = *(char **) (packet + ChatPacket_message_property_offset);
if (message[0] == '/') {
// API Command
unsigned char *gui = minecraft + Minecraft_gui_property_offset;
std::string out = chat_send_api_command(minecraft, &message[1]);
if (out.length() > 0 && out[out.length() - 1] == '\n') {
out[out.length() - 1] = '\0';
}
misc_add_message(gui, out.c_str());
} else {
// Call Original Method
ensure_chat_handle_packet_send();
(*real_chat_handle_packet_send)(minecraft, packet);
}
}

View File

@ -0,0 +1,15 @@
/out
/debian/tmp
/.vscode
/build*
/CMakeLists.txt.user
*.autosave
/AppImageBuilder.yml
/appimage-builder-cache
/appimage-build
/AppDir
/*.zsync
/*.AppImage
/core*
/qemu_*
/cmake/.prebuilt-armhf-toolchain

View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.16.0)
# Build For ARM
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
# Start Project
project(expanded-creative)
# Include SDK
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
# Build
add_library(expanded-creative SHARED expanded-creative.cpp)
target_link_libraries(expanded-creative mods-headers reborn-patch symbols misc)

View File

@ -0,0 +1,638 @@
// Headers
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/misc/misc.h>
// The Actual Mod
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container) {
ItemInstance *fire_instance = new ItemInstance;
ALLOC_CHECK(fire_instance);
fire_instance->count = 255;
fire_instance->auxiliary = 0;
fire_instance->id = 51;
(*FillingContainer_addItem)(filling_container, fire_instance);
ItemInstance *mushroomStew_instance = new ItemInstance;
ALLOC_CHECK(mushroomStew_instance);
mushroomStew_instance->count = 255;
mushroomStew_instance->auxiliary = 0;
mushroomStew_instance->id = 282;
(*FillingContainer_addItem)(filling_container, mushroomStew_instance);
ItemInstance *steak_instance = new ItemInstance;
ALLOC_CHECK(steak_instance);
steak_instance->count = 255;
steak_instance->auxiliary = 0;
steak_instance->id = 364;
(*FillingContainer_addItem)(filling_container, steak_instance);
ItemInstance *cookedChicken_instance = new ItemInstance;
ALLOC_CHECK(cookedChicken_instance);
cookedChicken_instance->count = 255;
cookedChicken_instance->auxiliary = 0;
cookedChicken_instance->id = 366;
(*FillingContainer_addItem)(filling_container, cookedChicken_instance);
ItemInstance *porkCooked_instance = new ItemInstance;
ALLOC_CHECK(porkCooked_instance);
porkCooked_instance->count = 255;
porkCooked_instance->auxiliary = 0;
porkCooked_instance->id = 320;
(*FillingContainer_addItem)(filling_container, porkCooked_instance);
ItemInstance *apple_instance = new ItemInstance;
ALLOC_CHECK(apple_instance);
apple_instance->count = 255;
apple_instance->auxiliary = 0;
apple_instance->id = 260;
(*FillingContainer_addItem)(filling_container, apple_instance);
ItemInstance *tallGrass_instance = new ItemInstance;
ALLOC_CHECK(tallGrass_instance);
tallGrass_instance->count = 255;
tallGrass_instance->auxiliary = 0;
tallGrass_instance->id = 31;
(*FillingContainer_addItem)(filling_container, tallGrass_instance);
ItemInstance *crops_instance = new ItemInstance;
ALLOC_CHECK(crops_instance);
crops_instance->count = 255;
crops_instance->auxiliary = 0;
crops_instance->id = 59;
(*FillingContainer_addItem)(filling_container, crops_instance);
ItemInstance *farmland_instance = new ItemInstance;
ALLOC_CHECK(farmland_instance);
farmland_instance->count = 255;
farmland_instance->auxiliary = 0;
farmland_instance->id = 60;
(*FillingContainer_addItem)(filling_container, farmland_instance);
ItemInstance *activeFurnace_instance = new ItemInstance;
ALLOC_CHECK(activeFurnace_instance);
activeFurnace_instance->count = 255;
activeFurnace_instance->auxiliary = 0;
activeFurnace_instance->id = 62;
(*FillingContainer_addItem)(filling_container, activeFurnace_instance);
ItemInstance *ironDoor_instance = new ItemInstance;
ALLOC_CHECK(ironDoor_instance);
ironDoor_instance->count = 255;
ironDoor_instance->auxiliary = 0;
ironDoor_instance->id = 330;
(*FillingContainer_addItem)(filling_container, ironDoor_instance);
ItemInstance *activeRedstoneOre_instance = new ItemInstance;
ALLOC_CHECK(activeRedstoneOre_instance);
activeRedstoneOre_instance->count = 255;
activeRedstoneOre_instance->auxiliary = 0;
activeRedstoneOre_instance->id = 74;
(*FillingContainer_addItem)(filling_container, activeRedstoneOre_instance);
ItemInstance *pumkinStem_instance = new ItemInstance;
ALLOC_CHECK(pumkinStem_instance);
pumkinStem_instance->count = 255;
pumkinStem_instance->auxiliary = 0;
pumkinStem_instance->id = 105;
(*FillingContainer_addItem)(filling_container, pumkinStem_instance);
ItemInstance *newGrass_instance = new ItemInstance;
ALLOC_CHECK(newGrass_instance);
newGrass_instance->count = 255;
newGrass_instance->auxiliary = 0;
newGrass_instance->id = 253;
(*FillingContainer_addItem)(filling_container, newGrass_instance);
ItemInstance *reserved6_instance = new ItemInstance;
ALLOC_CHECK(reserved6_instance);
reserved6_instance->count = 255;
reserved6_instance->auxiliary = 0;
reserved6_instance->id = 1;
(*FillingContainer_addItem)(filling_container, reserved6_instance);
ItemInstance *doubleStoneSlab_instance = new ItemInstance;
ALLOC_CHECK(doubleStoneSlab_instance);
doubleStoneSlab_instance->count = 255;
doubleStoneSlab_instance->auxiliary = 0;
doubleStoneSlab_instance->id = 43;
(*FillingContainer_addItem)(filling_container, doubleStoneSlab_instance);
ItemInstance *arrow_instance = new ItemInstance;
ALLOC_CHECK(arrow_instance);
arrow_instance->count = 255;
arrow_instance->auxiliary = 0;
arrow_instance->id = 262;
(*FillingContainer_addItem)(filling_container, arrow_instance);
ItemInstance *coal_instance = new ItemInstance;
ALLOC_CHECK(coal_instance);
coal_instance->count = 255;
coal_instance->auxiliary = 0;
coal_instance->id = 263;
(*FillingContainer_addItem)(filling_container, coal_instance);
ItemInstance *diamond_instance = new ItemInstance;
ALLOC_CHECK(diamond_instance);
diamond_instance->count = 255;
diamond_instance->auxiliary = 0;
diamond_instance->id = 264;
(*FillingContainer_addItem)(filling_container, diamond_instance);
ItemInstance *ironIngot_instance = new ItemInstance;
ALLOC_CHECK(ironIngot_instance);
ironIngot_instance->count = 255;
ironIngot_instance->auxiliary = 0;
ironIngot_instance->id = 265;
(*FillingContainer_addItem)(filling_container, ironIngot_instance);
ItemInstance *goldIngot_instance = new ItemInstance;
ALLOC_CHECK(goldIngot_instance);
goldIngot_instance->count = 255;
goldIngot_instance->auxiliary = 0;
goldIngot_instance->id = 266;
(*FillingContainer_addItem)(filling_container, goldIngot_instance);
ItemInstance *woodSword_instance = new ItemInstance;
ALLOC_CHECK(woodSword_instance);
woodSword_instance->count = 255;
woodSword_instance->auxiliary = 0;
woodSword_instance->id = 268;
(*FillingContainer_addItem)(filling_container, woodSword_instance);
ItemInstance *woodShovel_instance = new ItemInstance;
ALLOC_CHECK(woodShovel_instance);
woodShovel_instance->count = 255;
woodShovel_instance->auxiliary = 0;
woodShovel_instance->id = 269;
(*FillingContainer_addItem)(filling_container, woodShovel_instance);
ItemInstance *woodPickaxe_instance = new ItemInstance;
ALLOC_CHECK(woodPickaxe_instance);
woodPickaxe_instance->count = 255;
woodPickaxe_instance->auxiliary = 0;
woodPickaxe_instance->id = 270;
(*FillingContainer_addItem)(filling_container, woodPickaxe_instance);
ItemInstance *woodAxe_instance = new ItemInstance;
ALLOC_CHECK(woodAxe_instance);
woodAxe_instance->count = 255;
woodAxe_instance->auxiliary = 0;
woodAxe_instance->id = 271;
(*FillingContainer_addItem)(filling_container, woodAxe_instance);
ItemInstance *stoneSword_instance = new ItemInstance;
ALLOC_CHECK(stoneSword_instance);
stoneSword_instance->count = 255;
stoneSword_instance->auxiliary = 0;
stoneSword_instance->id = 272;
(*FillingContainer_addItem)(filling_container, stoneSword_instance);
ItemInstance *stoneShovel_instance = new ItemInstance;
ALLOC_CHECK(stoneShovel_instance);
stoneShovel_instance->count = 255;
stoneShovel_instance->auxiliary = 0;
stoneShovel_instance->id = 273;
(*FillingContainer_addItem)(filling_container, stoneShovel_instance);
ItemInstance *stonePickaxe_instance = new ItemInstance;
ALLOC_CHECK(stonePickaxe_instance);
stonePickaxe_instance->count = 255;
stonePickaxe_instance->auxiliary = 0;
stonePickaxe_instance->id = 274;
(*FillingContainer_addItem)(filling_container, stonePickaxe_instance);
ItemInstance *stoneAxe_instance = new ItemInstance;
ALLOC_CHECK(stoneAxe_instance);
stoneAxe_instance->count = 255;
stoneAxe_instance->auxiliary = 0;
stoneAxe_instance->id = 275;
(*FillingContainer_addItem)(filling_container, stoneAxe_instance);
ItemInstance *shovelIron_instance = new ItemInstance;
ALLOC_CHECK(shovelIron_instance);
shovelIron_instance->count = 255;
shovelIron_instance->auxiliary = 0;
shovelIron_instance->id = 256;
(*FillingContainer_addItem)(filling_container, shovelIron_instance);
ItemInstance *ironPick_instance = new ItemInstance;
ALLOC_CHECK(ironPick_instance);
ironPick_instance->count = 255;
ironPick_instance->auxiliary = 0;
ironPick_instance->id = 257;
(*FillingContainer_addItem)(filling_container, ironPick_instance);
ItemInstance *ironAxe_instance = new ItemInstance;
ALLOC_CHECK(ironAxe_instance);
ironAxe_instance->count = 255;
ironAxe_instance->auxiliary = 0;
ironAxe_instance->id = 258;
(*FillingContainer_addItem)(filling_container, ironAxe_instance);
ItemInstance *diamondSword_instance = new ItemInstance;
ALLOC_CHECK(diamondSword_instance);
diamondSword_instance->count = 255;
diamondSword_instance->auxiliary = 0;
diamondSword_instance->id = 276;
(*FillingContainer_addItem)(filling_container, diamondSword_instance);
ItemInstance *diamondShovel_instance = new ItemInstance;
ALLOC_CHECK(diamondShovel_instance);
diamondShovel_instance->count = 255;
diamondShovel_instance->auxiliary = 0;
diamondShovel_instance->id = 277;
(*FillingContainer_addItem)(filling_container, diamondShovel_instance);
ItemInstance *diamondPickaxe_instance = new ItemInstance;
ALLOC_CHECK(diamondPickaxe_instance);
diamondPickaxe_instance->count = 255;
diamondPickaxe_instance->auxiliary = 0;
diamondPickaxe_instance->id = 278;
(*FillingContainer_addItem)(filling_container, diamondPickaxe_instance);
ItemInstance *diamondAxe_instance = new ItemInstance;
ALLOC_CHECK(diamondAxe_instance);
diamondAxe_instance->count = 255;
diamondAxe_instance->auxiliary = 0;
diamondAxe_instance->id = 279;
(*FillingContainer_addItem)(filling_container, diamondAxe_instance);
ItemInstance *magicWand_instance = new ItemInstance;
ALLOC_CHECK(magicWand_instance);
magicWand_instance->count = 255;
magicWand_instance->auxiliary = 0;
magicWand_instance->id = 280;
(*FillingContainer_addItem)(filling_container, magicWand_instance);
ItemInstance *bowl_instance = new ItemInstance;
ALLOC_CHECK(bowl_instance);
bowl_instance->count = 255;
bowl_instance->auxiliary = 0;
bowl_instance->id = 281;
(*FillingContainer_addItem)(filling_container, bowl_instance);
ItemInstance *goldSword_instance = new ItemInstance;
ALLOC_CHECK(goldSword_instance);
goldSword_instance->count = 255;
goldSword_instance->auxiliary = 0;
goldSword_instance->id = 283;
(*FillingContainer_addItem)(filling_container, goldSword_instance);
ItemInstance *goldShovel_instance = new ItemInstance;
ALLOC_CHECK(goldShovel_instance);
goldShovel_instance->count = 255;
goldShovel_instance->auxiliary = 0;
goldShovel_instance->id = 284;
(*FillingContainer_addItem)(filling_container, goldShovel_instance);
ItemInstance *goldPickaxe_instance = new ItemInstance;
ALLOC_CHECK(goldPickaxe_instance);
goldPickaxe_instance->count = 255;
goldPickaxe_instance->auxiliary = 0;
goldPickaxe_instance->id = 285;
(*FillingContainer_addItem)(filling_container, goldPickaxe_instance);
ItemInstance *goldAxe_instance = new ItemInstance;
ALLOC_CHECK(goldAxe_instance);
goldAxe_instance->count = 255;
goldAxe_instance->auxiliary = 0;
goldAxe_instance->id = 286;
(*FillingContainer_addItem)(filling_container, goldAxe_instance);
ItemInstance *string_instance = new ItemInstance;
ALLOC_CHECK(string_instance);
string_instance->count = 255;
string_instance->auxiliary = 0;
string_instance->id = 287;
(*FillingContainer_addItem)(filling_container, string_instance);
ItemInstance *feather_instance = new ItemInstance;
ALLOC_CHECK(feather_instance);
feather_instance->count = 255;
feather_instance->auxiliary = 0;
feather_instance->id = 288;
(*FillingContainer_addItem)(filling_container, feather_instance);
ItemInstance *gunpowder_instance = new ItemInstance;
ALLOC_CHECK(gunpowder_instance);
gunpowder_instance->count = 255;
gunpowder_instance->auxiliary = 0;
gunpowder_instance->id = 289;
(*FillingContainer_addItem)(filling_container, gunpowder_instance);
ItemInstance *woodHoe_instance = new ItemInstance;
ALLOC_CHECK(woodHoe_instance);
woodHoe_instance->count = 255;
woodHoe_instance->auxiliary = 0;
woodHoe_instance->id = 290;
(*FillingContainer_addItem)(filling_container, woodHoe_instance);
ItemInstance *stoneHoe_instance = new ItemInstance;
ALLOC_CHECK(stoneHoe_instance);
stoneHoe_instance->count = 255;
stoneHoe_instance->auxiliary = 0;
stoneHoe_instance->id = 291;
(*FillingContainer_addItem)(filling_container, stoneHoe_instance);
ItemInstance *flint1_instance = new ItemInstance;
ALLOC_CHECK(flint1_instance);
flint1_instance->count = 255;
flint1_instance->auxiliary = 0;
flint1_instance->id = 292;
(*FillingContainer_addItem)(filling_container, flint1_instance);
ItemInstance *diamondHoe_instance = new ItemInstance;
ALLOC_CHECK(diamondHoe_instance);
diamondHoe_instance->count = 255;
diamondHoe_instance->auxiliary = 0;
diamondHoe_instance->id = 293;
(*FillingContainer_addItem)(filling_container, diamondHoe_instance);
ItemInstance *goldHoe_instance = new ItemInstance;
ALLOC_CHECK(goldHoe_instance);
goldHoe_instance->count = 255;
goldHoe_instance->auxiliary = 0;
goldHoe_instance->id = 294;
(*FillingContainer_addItem)(filling_container, goldHoe_instance);
ItemInstance *seeds_instance = new ItemInstance;
ALLOC_CHECK(seeds_instance);
seeds_instance->count = 255;
seeds_instance->auxiliary = 0;
seeds_instance->id = 295;
(*FillingContainer_addItem)(filling_container, seeds_instance);
ItemInstance *wheat_instance = new ItemInstance;
ALLOC_CHECK(wheat_instance);
wheat_instance->count = 255;
wheat_instance->auxiliary = 0;
wheat_instance->id = 296;
(*FillingContainer_addItem)(filling_container, wheat_instance);
ItemInstance *bread_instance = new ItemInstance;
ALLOC_CHECK(bread_instance);
bread_instance->count = 255;
bread_instance->auxiliary = 0;
bread_instance->id = 297;
(*FillingContainer_addItem)(filling_container, bread_instance);
ItemInstance *diamondHelm_instance = new ItemInstance;
ALLOC_CHECK(diamondHelm_instance);
diamondHelm_instance->count = 255;
diamondHelm_instance->auxiliary = 0;
diamondHelm_instance->id = 310;
(*FillingContainer_addItem)(filling_container, diamondHelm_instance);
ItemInstance *diamondChest_instance = new ItemInstance;
ALLOC_CHECK(diamondChest_instance);
diamondChest_instance->count = 255;
diamondChest_instance->auxiliary = 0;
diamondChest_instance->id = 311;
(*FillingContainer_addItem)(filling_container, diamondChest_instance);
ItemInstance *diamondLeg_instance = new ItemInstance;
ALLOC_CHECK(diamondLeg_instance);
diamondLeg_instance->count = 255;
diamondLeg_instance->auxiliary = 0;
diamondLeg_instance->id = 312;
(*FillingContainer_addItem)(filling_container, diamondLeg_instance);
ItemInstance *diamondBoot_instance = new ItemInstance;
ALLOC_CHECK(diamondBoot_instance);
diamondBoot_instance->count = 255;
diamondBoot_instance->auxiliary = 0;
diamondBoot_instance->id = 313;
(*FillingContainer_addItem)(filling_container, diamondBoot_instance);
ItemInstance *leatherCap_instance = new ItemInstance;
ALLOC_CHECK(leatherCap_instance);
leatherCap_instance->count = 255;
leatherCap_instance->auxiliary = 0;
leatherCap_instance->id = 298;
(*FillingContainer_addItem)(filling_container, leatherCap_instance);
ItemInstance *leatherShirt_instance = new ItemInstance;
ALLOC_CHECK(leatherShirt_instance);
leatherShirt_instance->count = 255;
leatherShirt_instance->auxiliary = 0;
leatherShirt_instance->id = 299;
(*FillingContainer_addItem)(filling_container, leatherShirt_instance);
ItemInstance *leatherPants_instance = new ItemInstance;
ALLOC_CHECK(leatherPants_instance);
leatherPants_instance->count = 255;
leatherPants_instance->auxiliary = 0;
leatherPants_instance->id = 300;
(*FillingContainer_addItem)(filling_container, leatherPants_instance);
ItemInstance *leatherBoots_instance = new ItemInstance;
ALLOC_CHECK(leatherBoots_instance);
leatherBoots_instance->count = 255;
leatherBoots_instance->auxiliary = 0;
leatherBoots_instance->id = 301;
(*FillingContainer_addItem)(filling_container, leatherBoots_instance);
ItemInstance *chainHelm_instance = new ItemInstance;
ALLOC_CHECK(chainHelm_instance);
chainHelm_instance->count = 255;
chainHelm_instance->auxiliary = 0;
chainHelm_instance->id = 302;
(*FillingContainer_addItem)(filling_container, chainHelm_instance);
ItemInstance *chainShirt_instance = new ItemInstance;
ALLOC_CHECK(chainShirt_instance);
chainShirt_instance->count = 255;
chainShirt_instance->auxiliary = 0;
chainShirt_instance->id = 303;
(*FillingContainer_addItem)(filling_container, chainShirt_instance);
ItemInstance *chainLegs_instance = new ItemInstance;
ALLOC_CHECK(chainLegs_instance);
chainLegs_instance->count = 255;
chainLegs_instance->auxiliary = 0;
chainLegs_instance->id = 304;
(*FillingContainer_addItem)(filling_container, chainLegs_instance);
ItemInstance *chainBoots_instance = new ItemInstance;
ALLOC_CHECK(chainBoots_instance);
chainBoots_instance->count = 255;
chainBoots_instance->auxiliary = 0;
chainBoots_instance->id = 305;
(*FillingContainer_addItem)(filling_container, chainBoots_instance);
ItemInstance *goldHelm_instance = new ItemInstance;
ALLOC_CHECK(goldHelm_instance);
goldHelm_instance->count = 255;
goldHelm_instance->auxiliary = 0;
goldHelm_instance->id = 314;
(*FillingContainer_addItem)(filling_container, goldHelm_instance);
ItemInstance *goldChest_instance = new ItemInstance;
ALLOC_CHECK(goldChest_instance);
goldChest_instance->count = 255;
goldChest_instance->auxiliary = 0;
goldChest_instance->id = 315;
(*FillingContainer_addItem)(filling_container, goldChest_instance);
ItemInstance *goldLegs_instance = new ItemInstance;
ALLOC_CHECK(goldLegs_instance);
goldLegs_instance->count = 255;
goldLegs_instance->auxiliary = 0;
goldLegs_instance->id = 316;
(*FillingContainer_addItem)(filling_container, goldLegs_instance);
ItemInstance *goldBoots_instance = new ItemInstance;
ALLOC_CHECK(goldBoots_instance);
goldBoots_instance->count = 255;
goldBoots_instance->auxiliary = 0;
goldBoots_instance->id = 317;
(*FillingContainer_addItem)(filling_container, goldBoots_instance);
ItemInstance *ironHelm_instance = new ItemInstance;
ALLOC_CHECK(ironHelm_instance);
ironHelm_instance->count = 255;
ironHelm_instance->auxiliary = 0;
ironHelm_instance->id = 306;
(*FillingContainer_addItem)(filling_container, ironHelm_instance);
ItemInstance *ironChest_instance = new ItemInstance;
ALLOC_CHECK(ironChest_instance);
ironChest_instance->count = 255;
ironChest_instance->auxiliary = 0;
ironChest_instance->id = 307;
(*FillingContainer_addItem)(filling_container, ironChest_instance);
ItemInstance *ironLegs_instance = new ItemInstance;
ALLOC_CHECK(ironLegs_instance);
ironLegs_instance->count = 255;
ironLegs_instance->auxiliary = 0;
ironLegs_instance->id = 308;
(*FillingContainer_addItem)(filling_container, ironLegs_instance);
ItemInstance *ironBoots_instance = new ItemInstance;
ALLOC_CHECK(ironBoots_instance);
ironBoots_instance->count = 255;
ironBoots_instance->auxiliary = 0;
ironBoots_instance->id = 309;
(*FillingContainer_addItem)(filling_container, ironBoots_instance);
ItemInstance *flint2_instance = new ItemInstance;
ALLOC_CHECK(flint2_instance);
flint2_instance->count = 255;
flint2_instance->auxiliary = 0;
flint2_instance->id = 318;
(*FillingContainer_addItem)(filling_container, flint2_instance);
ItemInstance *porkRaw_instance = new ItemInstance;
ALLOC_CHECK(porkRaw_instance);
porkRaw_instance->count = 255;
porkRaw_instance->auxiliary = 0;
porkRaw_instance->id = 319;
(*FillingContainer_addItem)(filling_container, porkRaw_instance);
ItemInstance *leather_instance = new ItemInstance;
ALLOC_CHECK(leather_instance);
leather_instance->count = 255;
leather_instance->auxiliary = 0;
leather_instance->id = 334;
(*FillingContainer_addItem)(filling_container, leather_instance);
ItemInstance *clayBrick_instance = new ItemInstance;
ALLOC_CHECK(clayBrick_instance);
clayBrick_instance->count = 255;
clayBrick_instance->auxiliary = 0;
clayBrick_instance->id = 336;
(*FillingContainer_addItem)(filling_container, clayBrick_instance);
ItemInstance *clay_instance = new ItemInstance;
ALLOC_CHECK(clay_instance);
clay_instance->count = 255;
clay_instance->auxiliary = 0;
clay_instance->id = 337;
(*FillingContainer_addItem)(filling_container, clay_instance);
ItemInstance *notepad_instance = new ItemInstance;
ALLOC_CHECK(notepad_instance);
notepad_instance->count = 255;
notepad_instance->auxiliary = 0;
notepad_instance->id = 339;
(*FillingContainer_addItem)(filling_container, notepad_instance);
ItemInstance *book_instance = new ItemInstance;
ALLOC_CHECK(book_instance);
book_instance->count = 255;
book_instance->auxiliary = 0;
book_instance->id = 340;
(*FillingContainer_addItem)(filling_container, book_instance);
ItemInstance *slimeball_instance = new ItemInstance;
ALLOC_CHECK(slimeball_instance);
slimeball_instance->count = 255;
slimeball_instance->auxiliary = 0;
slimeball_instance->id = 341;
(*FillingContainer_addItem)(filling_container, slimeball_instance);
ItemInstance *compass_instance = new ItemInstance;
ALLOC_CHECK(compass_instance);
compass_instance->count = 255;
compass_instance->auxiliary = 0;
compass_instance->id = 345;
(*FillingContainer_addItem)(filling_container, compass_instance);
ItemInstance *clock_instance = new ItemInstance;
ALLOC_CHECK(clock_instance);
clock_instance->count = 255;
clock_instance->auxiliary = 0;
clock_instance->id = 347;
(*FillingContainer_addItem)(filling_container, clock_instance);
ItemInstance *glowDust_instance = new ItemInstance;
ALLOC_CHECK(glowDust_instance);
glowDust_instance->count = 255;
glowDust_instance->auxiliary = 0;
glowDust_instance->id = 348;
(*FillingContainer_addItem)(filling_container, glowDust_instance);
ItemInstance *bone_instance = new ItemInstance;
ALLOC_CHECK(bone_instance);
bone_instance->count = 255;
bone_instance->auxiliary = 0;
bone_instance->id = 352;
(*FillingContainer_addItem)(filling_container, bone_instance);
ItemInstance *sugar_instance = new ItemInstance;
ALLOC_CHECK(sugar_instance);
sugar_instance->count = 255;
sugar_instance->auxiliary = 0;
sugar_instance->id = 353;
(*FillingContainer_addItem)(filling_container, sugar_instance);
ItemInstance *melon_instance = new ItemInstance;
ALLOC_CHECK(melon_instance);
melon_instance->count = 255;
melon_instance->auxiliary = 0;
melon_instance->id = 360;
(*FillingContainer_addItem)(filling_container, melon_instance);
ItemInstance *beefRaw_instance = new ItemInstance;
ALLOC_CHECK(beefRaw_instance);
beefRaw_instance->count = 255;
beefRaw_instance->auxiliary = 0;
beefRaw_instance->id = 363;
(*FillingContainer_addItem)(filling_container, beefRaw_instance);
ItemInstance *chickenRaw_instance = new ItemInstance;
ALLOC_CHECK(chickenRaw_instance);
chickenRaw_instance->count = 255;
chickenRaw_instance->auxiliary = 0;
chickenRaw_instance->id = 365;
(*FillingContainer_addItem)(filling_container, chickenRaw_instance);
}
// Init
__attribute__((constructor)) static void init_expanded_creative() {
INFO("Loading Expanded Creative Mod");
misc_run_on_creative_inventory_setup(Inventory_setupDefault_FillingContainer_addItem_call_injection);
}

15
example-mods/recipes/.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
/out
/debian/tmp
/.vscode
/build*
/CMakeLists.txt.user
*.autosave
/AppImageBuilder.yml
/appimage-builder-cache
/appimage-build
/AppDir
/*.zsync
/*.AppImage
/core*
/qemu_*
/cmake/.prebuilt-armhf-toolchain

View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.16.0)
# Build For ARM
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
# Start Project
project(recipes)
# Include SDK
include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake")
# Build
add_library(recipes SHARED recipes.cpp)
target_link_libraries(recipes mods-headers reborn-util symbols misc)

View File

@ -0,0 +1,52 @@
// Headers
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/misc/misc.h>
// Custom Crafting Recipes
static void Recipes_injection(unsigned char *recipes) {
// Add
Recipes_Type type1 = {
.item = 0,
.tile = 0,
.instance = {
.count = 1,
.id = 12,
.auxiliary = 0
},
.letter = 'a'
};
Recipes_Type type2 = {
.item = 0,
.tile = 0,
.instance = {
.count = 1,
.id = 13,
.auxiliary = 0
},
.letter = 'b'
};
ItemInstance result = {
.count = 1,
.id = 344,
.auxiliary = 0
};
(*Recipes_addShapelessRecipe)(recipes, result, {type1, type2});
}
// Custom Furnace Recipes
static void FurnaceRecipes_injection(unsigned char *recipes) {
// Add
(*FurnaceRecipes_addFurnaceRecipe)(recipes, 49, {.count = 1, .id = 246, .auxiliary = 0});
}
// Init
__attribute__((constructor)) static void init_recipes() {
// Log
INFO("Loading Custom Recipes");
// Setup
misc_run_on_recipes_setup(Recipes_injection);
misc_run_on_furnace_recipes_setup(FurnaceRecipes_injection);
}

23
images/CMakeLists.txt Normal file
View File

@ -0,0 +1,23 @@
project(images)
# Title Background
if(NOT MCPI_HEADLESS_MODE)
install(
FILES "background.png"
DESTINATION "${MCPI_INSTALL_DIR}/data/images/gui"
RENAME "titleBG.png"
)
endif()
# Icon
install(
FILES "icon.png"
DESTINATION "${MCPI_SHARE_DIR}/icons/hicolor/scalable/apps"
RENAME "${MCPI_APP_ID}.png"
)
# AppImage
if(MCPI_IS_APPIMAGE_BUILD)
install_symlink("${MCPI_SHARE_DIR}/icons/hicolor/scalable/apps/${MCPI_APP_ID}.png" "${MCPI_APP_ID}.png")
install_symlink("${MCPI_APP_ID}.png" ".DirIcon")
endif()

BIN
images/background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

BIN
images/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 155 KiB

View File

@ -1,18 +1,117 @@
project(launcher)
# Dependencies
add_subdirectory(dependencies)
# Launcher
if(BUILD_NATIVE_COMPONENTS)
add_executable(launcher src/bootstrap.c src/ldconfig.cpp)
if(MCPI_SERVER_MODE)
target_sources(launcher PRIVATE src/server/launcher.c)
else()
target_sources(launcher PRIVATE src/client/launcher.cpp)
endif()
target_link_libraries(launcher reborn-headers)
# Install
install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}")
install_symlink("../../${MCPI_INSTALL_DIR}/launcher" "usr/bin/${MCPI_VARIANT_NAME}")
if(NOT MCPI_SERVER_MODE)
install(DIRECTORY "client-data/" DESTINATION ".")
endif()
add_executable(launcher src/bootstrap.c src/patchelf.c src/crash-report.c)
if(MCPI_SERVER_MODE)
target_sources(launcher PRIVATE src/server/launcher.c)
else()
embed_resource(launcher src/client/available-feature-flags)
target_sources(launcher PRIVATE src/client/launcher.cpp)
endif()
target_link_libraries(launcher reborn-util)
# RPath
set_target_properties(launcher PROPERTIES INSTALL_RPATH "$ORIGIN/lib/native")
# Install
install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}")
install_symlink("../${MCPI_INSTALL_DIR}/launcher" "bin/${MCPI_VARIANT_NAME}")
# Install Desktop Entry
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
"[Desktop Entry]\n"
"Name=${MCPI_APP_TITLE}\n"
"Comment=Fun with Blocks\n"
"Icon=${MCPI_APP_ID}\n"
"Exec=${MCPI_VARIANT_NAME}\n"
"Type=Application\n"
"Categories=Game;\n"
)
if(MCPI_HEADLESS_MODE)
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
"Terminal=true\n"
"NoDisplay=true\n"
)
else()
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
"Terminal=false\n"
"StartupNotify=false\n"
"StartupWMClass=${MCPI_APP_ID}\n"
)
endif()
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/launcher.desktop"
DESTINATION "${MCPI_SHARE_DIR}/applications"
RENAME "${MCPI_APP_ID}.desktop"
)
# Install AppStream Metadata
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/appstream.xml"
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<component type=\"desktop\">\n"
" <id>${MCPI_APP_ID}</id>\n"
" <name>${MCPI_APP_TITLE}</name>\n"
" <metadata_license>CC0-1.0</metadata_license>\n"
" <summary>Fun with Blocks</summary>\n"
" <description>\n"
" <p>Minecraft: Pi Edition Modding Project.</p>\n"
" <p>NOTE: This is not verified by, affiliated with, or supported by Mojang or Microsoft.</p>\n"
" </description>\n"
" <url type=\"homepage\">https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn</url>\n"
" <launchable type=\"desktop-id\">${MCPI_APP_ID}.desktop</launchable>\n"
" <provides>\n"
" <id>com.thebrokenrail.MCPIRebornClient.desktop</id>\n"
" </provides>\n"
" <project_license>LicenseRef-proprietary</project_license>\n"
" <developer_name>TheBrokenRail &amp; Mojang AB</developer_name>\n"
" <content_rating type=\"oars-1.0\">\n"
" <content_attribute id=\"violence-cartoon\">moderate</content_attribute>\n"
" <content_attribute id=\"violence-fantasy\">none</content_attribute>\n"
" <content_attribute id=\"violence-realistic\">none</content_attribute>\n"
" <content_attribute id=\"violence-bloodshed\">none</content_attribute>\n"
" <content_attribute id=\"violence-sexual\">none</content_attribute>\n"
" <content_attribute id=\"drugs-alcohol\">none</content_attribute>\n"
" <content_attribute id=\"drugs-narcotics\">none</content_attribute>\n"
" <content_attribute id=\"drugs-tobacco\">none</content_attribute>\n"
" <content_attribute id=\"sex-nudity\">none</content_attribute>\n"
" <content_attribute id=\"sex-themes\">none</content_attribute>\n"
" <content_attribute id=\"language-profanity\">none</content_attribute>\n"
" <content_attribute id=\"language-humor\">none</content_attribute>\n"
" <content_attribute id=\"language-discrimination\">none</content_attribute>\n"
" <content_attribute id=\"social-chat\">intense</content_attribute>\n"
" <content_attribute id=\"social-info\">none</content_attribute>\n"
" <content_attribute id=\"social-audio\">none</content_attribute>\n"
" <content_attribute id=\"social-location\">none</content_attribute>\n"
" <content_attribute id=\"social-contacts\">none</content_attribute>\n"
" <content_attribute id=\"money-purchasing\">none</content_attribute>\n"
" <content_attribute id=\"money-gambling\">none</content_attribute>\n"
" </content_rating>\n"
" <releases>\n"
" <release version=\"${MCPI_VERSION}\" date=\"${MCPI_VERSION_DATE}\"></release>\n"
" </releases>\n"
)
if(NOT MCPI_HEADLESS_MODE)
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/appstream.xml"
" <screenshots>\n"
" <screenshot type=\"default\">\n"
" <image>https://gitea.thebrokenrail.com/TheBrokenRail/minecraft-pi-reborn/raw/branch/master/images/start.png</image>\n"
" </screenshot>\n"
" </screenshots>\n"
)
endif()
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/appstream.xml"
"</component>\n"
)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/appstream.xml"
DESTINATION "${MCPI_SHARE_DIR}/metainfo"
RENAME "${MCPI_APP_ID}.appdata.xml"
)
# AppImage
if(MCPI_IS_APPIMAGE_BUILD)
install_symlink("bin/${MCPI_VARIANT_NAME}" "AppRun")
install_symlink("${MCPI_SHARE_DIR}/applications/${MCPI_APP_ID}.desktop" "${MCPI_APP_ID}.desktop")
endif()

View File

@ -1,26 +0,0 @@
TRUE Touch GUI
TRUE Fix Bow & Arrow
TRUE Fix Attacking
FALSE Force Mob Spawning
TRUE Fancy Graphics
TRUE Disable Autojump By Default
TRUE Display Nametags By Default
TRUE Fix Sign Placement
TRUE Show Block Outlines
FALSE Expand Creative Inventory
FALSE Peaceful Mode
TRUE Animated Water
TRUE Remove Invalid Item Background
TRUE Disable "gui_blocks" Atlas
TRUE Smooth Lighting
FALSE 3D Anaglyph
TRUE Fix Camera Rendering
TRUE Implement Chat
TRUE Implement Death Messages
TRUE Implement Game-Mode Switching
TRUE Miscellaneous Input Fixes
TRUE Bind "Q" Key To Item Dropping
TRUE Bind Common Toggleable Options To Function Keys
TRUE Render Selected Item Text
TRUE External Server Support
TRUE Load Language Files

View File

@ -1,10 +0,0 @@
[Desktop Entry]
Name=Minecraft: Pi Edition: Reborn
Comment=Fun with Blocks
Icon=/usr/share/pixmaps/minecraft-pi-reborn-client.png
StartupNotify=false
StartupWMClass=Minecraft: Pi Edition: Reborn
Exec=/usr/bin/minecraft-pi-reborn-client
Terminal=false
Type=Application
Categories=Application;Game;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

View File

@ -0,0 +1,4 @@
project(launcher-dependencies)
# PatchELF
add_subdirectory(patchelf)

View File

@ -0,0 +1,17 @@
project(patchelf)
# Silence Warnings
add_compile_options(-w)
## PatchELF
# Build
add_executable(patchelf src/src/patchelf.cc)
target_compile_definitions(patchelf PRIVATE -D_FILE_OFFSET_BITS=64)
set_target_properties(patchelf PROPERTIES CXX_STANDARD 17)
# Install
install(TARGETS patchelf DESTINATION "${MCPI_BIN_DIR}")
# License
install(FILES src/COPYING DESTINATION "${MCPI_LEGAL_DIR}/patchelf")

@ -0,0 +1 @@
Subproject commit c2b419dc2a0d6095eaa69b65ad5854ce847bdd01

View File

@ -11,44 +11,8 @@
#include <libreborn/libreborn.h>
#include "bootstrap.h"
#include "ldconfig.h"
// Set Environmental Variable
#define PRESERVE_ENVIRONMENTAL_VARIABLE(name) \
{ \
char *original_env_value = getenv(name); \
if (original_env_value != NULL) { \
setenv("ORIGINAL_" name, original_env_value, 1); \
} \
}
static void trim(char **value) {
// Remove Trailing Colon
int length = strlen(*value);
if ((*value)[length - 1] == ':') {
(*value)[length - 1] = '\0';
}
if ((*value)[0] == ':') {
*value = &(*value)[1];
}
}
static void set_and_print_env(const char *name, char *value) {
// Set Variable With No Trailing Colon
trim(&value);
#ifdef DEBUG
// Print New Value
INFO("Set %s = %s", name, value);
#endif
// Set The Value
setenv(name, value, 1);
}
// Get Environmental Variable
static char *get_env_safe(const char *name) {
// Get Variable Or Blank String If Not Set
char *ret = getenv(name);
return ret != NULL ? ret : "";
}
#include "patchelf.h"
#include "crash-report.h"
// Get All Mods In Folder
static void load(char **ld_preload, char *folder) {
@ -82,14 +46,14 @@ static void load(char **ld_preload, char *folder) {
// Add Terminator
name[total_length] = '\0';
// Check If File Is Executable
// Check If File Is Accessible
int result = access(name, R_OK);
if (result == 0) {
// Add To LD_PRELOAD
string_append(ld_preload, ":%s", name);
string_append(ld_preload, "%s%s", *ld_preload == NULL ? "" : ":", name);
} else if (result == -1 && errno != 0) {
// Fail
INFO("Unable To Acesss: %s: %s", name, strerror(errno));
WARN("Unable To Access: %s: %s", name, strerror(errno));
errno = 0;
}
}
@ -121,102 +85,382 @@ static void load(char **ld_preload, char *folder) {
}
}
#define MCPI_NAME "minecraft-pi"
#define MCPI_BINARY "minecraft-pi"
#define QEMU_BINARY "qemu-arm"
// Bootstrap
void bootstrap(int argc, char *argv[]) {
INFO("%s", "Configuring Game...");
// Exit Handler
static void exit_handler(__attribute__((unused)) int signal_id) {
// Pass Signal To Child
murder_children();
while (wait(NULL) > 0) {}
_exit(EXIT_SUCCESS);
}
// Pre-Bootstrap
void pre_bootstrap(int argc, char *argv[]) {
// Disable stdout Buffering
setvbuf(stdout, NULL, _IONBF, 0);
// Set Default Native Component Environment
#define set_variable_default(name) set_and_print_env("MCPI_NATIVE_" name, getenv(name));
for_each_special_environmental_variable(set_variable_default);
// Print Version
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) {
// Print
printf("Reborn v%s\n", MCPI_VERSION);
fflush(stdout);
exit(EXIT_SUCCESS);
}
}
// GTK Dark Mode
#ifndef MCPI_SERVER_MODE
set_and_print_env("GTK_THEME", "Adwaita:dark");
#endif
// Debug Zenity
#ifndef MCPI_SERVER_MODE
{
const char *is_debug = getenv("MCPI_DEBUG");
if (is_debug != NULL && strlen(is_debug) > 0) {
set_and_print_env("ZENITY_DEBUG", "1");
}
}
#endif
// AppImage
#ifdef MCPI_IS_APPIMAGE_BUILD
{
char *owd = getenv("OWD");
if (owd != NULL && chdir(owd) != 0) {
ERR("AppImage: Unable To Fix Current Directory: %s", strerror(errno));
}
}
#endif
// Get Binary Directory
char *binary_directory = get_binary_directory();
// Configure LD_LIBRARY_PATH
// Configure PATH
{
PRESERVE_ENVIRONMENTAL_VARIABLE("LD_LIBRARY_PATH");
// Add Library Directory
char *new_ld_path;
safe_asprintf(&new_ld_path, "%s/lib", binary_directory);
// Add Existing LD_LIBRAR_PATH
char *new_path = NULL;
safe_asprintf(&new_path, "%s/bin", binary_directory);
// Add Existing PATH
{
char *value = get_env_safe("LD_LIBRARY_PATH");
if (strlen(value) > 0) {
string_append(&new_ld_path, ":%s", value);
char *value = getenv("PATH");
if (value != NULL && strlen(value) > 0) {
string_append(&new_path, ":%s", value);
}
}
// Load ARM Libraries
#ifdef __ARM_ARCH
string_append(&new_ld_path, "%s", ":/usr/lib/arm-linux-gnueabihf:/usr/arm-linux-gnueabihf/lib");
#endif
// Add Full Library Search Path
{
char *value = get_full_library_search_path();
if (strlen(value) > 0) {
string_append(&new_ld_path, ":%s", value);
}
free(value);
}
// Add Fallback Library Directory
string_append(&new_ld_path, ":%s/fallback-lib", binary_directory);
// Set And Free
set_and_print_env("LD_LIBRARY_PATH", new_ld_path);
free(new_ld_path);
set_and_print_env("PATH", new_path);
free(new_path);
}
// Configure LD_PRELOAD
// Free Binary Directory
free(binary_directory);
// Setup Crash Reports
setup_crash_report();
// Install Signal Handlers
struct sigaction act_sigint;
memset((void *) &act_sigint, 0, sizeof (struct sigaction));
act_sigint.sa_flags = SA_RESTART;
act_sigint.sa_handler = &exit_handler;
sigaction(SIGINT, &act_sigint, NULL);
struct sigaction act_sigterm;
memset((void *) &act_sigterm, 0, sizeof (struct sigaction));
act_sigterm.sa_flags = SA_RESTART;
act_sigterm.sa_handler = &exit_handler;
sigaction(SIGTERM, &act_sigterm, NULL);
}
// Copy SDK Into ~/.minecraft-pi
static void run_simple_command(const char *const command[], const char *error) {
int status = 0;
char *output = run_command(command, &status);
if (output != NULL) {
free(output);
}
if (!is_exit_status_success(status)) {
ERR("%s", error);
}
}
static void copy_sdk(char *binary_directory) {
// Output Directory
char *output = NULL;
safe_asprintf(&output, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA "/sdk/" MCPI_SDK_DIR, getenv("HOME"));
// Source Directory
char *source = NULL;
safe_asprintf(&source, "%s/sdk/.", binary_directory);
// Clean
{
PRESERVE_ENVIRONMENTAL_VARIABLE("LD_PRELOAD");
char *new_ld_preload = NULL;
safe_asprintf(&new_ld_preload, "%s", get_env_safe("LD_PRELOAD"));
const char *const command[] = {"rm", "-rf", output, NULL};
run_simple_command(command, "Unable To Clean SDK Output Directory");
}
// Get Mods Folder
char *mods_folder = NULL;
safe_asprintf(&mods_folder, "%s/mods/", binary_directory);
// Load Mods From ./mods
load(&new_ld_preload, mods_folder);
// Free Mods Folder
free(mods_folder);
// Make Directory
{
const char *const command[] = {"mkdir", "-p", output, NULL};
run_simple_command(command, "Unable To Create SDK Output Directory");
}
// Set LD_PRELOAD
set_and_print_env("LD_PRELOAD", new_ld_preload);
free(new_ld_preload);
// Copy
{
const char *const command[] = {"cp", "-ar", source, output, NULL};
run_simple_command(command, "Unable To Copy SDK");
}
// Free
free(output);
free(source);
}
// Bootstrap
void bootstrap(int argc, char *argv[]) {
INFO("Configuring Game...");
// Get Binary Directory
char *binary_directory = get_binary_directory();
// Copy SDK
copy_sdk(binary_directory);
// Set MCPI_REBORN_ASSETS_PATH
{
char *assets_path = realpath("/proc/self/exe", NULL);
ALLOC_CHECK(assets_path);
chop_last_component(&assets_path);
string_append(&assets_path, "/data");
set_and_print_env("MCPI_REBORN_ASSETS_PATH", assets_path);
free(assets_path);
}
// Resolve Binary Path & Set MCPI_DIRECTORY
char *resolved_path = NULL;
{
// Log
DEBUG("Resolving File Paths...");
// Resolve Full Binary Path
char *full_path = NULL;
safe_asprintf(&full_path, "%s/" MCPI_BINARY, binary_directory);
resolved_path = realpath(full_path, NULL);
ALLOC_CHECK(resolved_path);
free(full_path);
}
// Fix MCPI Dependencies
char new_mcpi_exe_path[] = MCPI_PATCHED_DIR "/XXXXXX";
{
// Log
DEBUG("Patching ELF Dependencies...");
// Find Linker
char *linker = NULL;
// Select Linker
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
// Use ARM Sysroot Linker
safe_asprintf(&linker, "%s/sysroot/lib/ld-linux-armhf.so.3", binary_directory);
#else
// Use Current Linker
char *exe = realpath("/proc/self/exe", NULL);
ALLOC_CHECK(exe);
linker = patch_get_interpreter(exe);
free(exe);
#endif
// Patch
patch_mcpi_elf_dependencies(resolved_path, new_mcpi_exe_path, linker);
// Free Linker Path
if (linker != NULL) {
free(linker);
}
// Verify
if (!starts_with(new_mcpi_exe_path, MCPI_PATCHED_DIR)) {
IMPOSSIBLE();
}
}
// Set MCPI_VANILLA_ASSETS_PATH
{
char *assets_path = strdup(resolved_path);
ALLOC_CHECK(assets_path);
chop_last_component(&assets_path);
string_append(&assets_path, "/data");
set_and_print_env("MCPI_VANILLA_ASSETS_PATH", assets_path);
free(assets_path);
}
// Free Resolved Path
free(resolved_path);
// Configure Library Search Path
{
// Log
DEBUG("Setting Linker Search Paths...");
// Prepare
char *transitive_ld_path = NULL;
char *mcpi_ld_path = NULL;
// Library Search Path For Native Components
{
// Add Native Library Directory
safe_asprintf(&transitive_ld_path, "%s/lib/native", binary_directory);
// Add Host LD_LIBRARY_PATH
{
char *value = getenv("LD_LIBRARY_PATH");
if (value != NULL && strlen(value) > 0) {
string_append(&transitive_ld_path, ":%s", value);
}
}
// Set
set_and_print_env("MCPI_NATIVE_LD_LIBRARY_PATH", transitive_ld_path);
free(transitive_ld_path);
}
// Library Search Path For ARM Components
{
// Add ARM Library Directory
safe_asprintf(&mcpi_ld_path, "%s/lib/arm", binary_directory);
// Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
string_append(&mcpi_ld_path, ":%s/sysroot/lib:%s/sysroot/lib/arm-linux-gnueabihf:%s/sysroot/usr/lib:%s/sysroot/usr/lib/arm-linux-gnueabihf", binary_directory, binary_directory, binary_directory, binary_directory);
#endif
// Add Host LD_LIBRARY_PATH
{
char *value = getenv("LD_LIBRARY_PATH");
if (value != NULL && strlen(value) > 0) {
string_append(&mcpi_ld_path, ":%s", value);
}
}
// Set
set_and_print_env("MCPI_ARM_LD_LIBRARY_PATH", mcpi_ld_path);
free(mcpi_ld_path);
}
// Setup iconv
{
// Native Components
char *host_gconv_path = getenv("GCONV_PATH");
set_and_print_env("MCPI_NATIVE_GCONV_PATH", host_gconv_path);
// ARM Components
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
char *gconv_path = NULL;
safe_asprintf(&gconv_path, "%s/sysroot/usr/lib/gconv", binary_directory);
set_and_print_env("MCPI_ARM_GCONV_PATH", gconv_path);
free(gconv_path);
#else
set_and_print_env("MCPI_ARM_GCONV_PATH", host_gconv_path);
#endif
}
}
// Configure Preloaded Objects
{
// Log
DEBUG("Locating Mods...");
// Native Components
char *host_ld_preload = getenv("LD_PRELOAD");
set_and_print_env("MCPI_NATIVE_LD_PRELOAD", host_ld_preload);
// ARM Components
{
// Prepare
char *preload = NULL;
// ~/.minecraft-pi/mods
{
// Get Mods Folder
char *mods_folder = NULL;
safe_asprintf(&mods_folder, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA "/mods/", getenv("HOME"));
// Load Mods From ./mods
load(&preload, mods_folder);
// Free Mods Folder
free(mods_folder);
}
// Built-In Mods
{
// Get Mods Folder
char *mods_folder = NULL;
safe_asprintf(&mods_folder, "%s/mods/", binary_directory);
// Load Mods From ./mods
load(&preload, mods_folder);
// Free Mods Folder
free(mods_folder);
}
// Add LD_PRELOAD
{
char *value = getenv("LD_PRELOAD");
if (value != NULL && strlen(value) > 0) {
string_append(&preload, ":%s", value);
}
}
// Set
set_and_print_env("MCPI_ARM_LD_PRELOAD", preload);
free(preload);
}
}
// Free Binary Directory
free(binary_directory);
// Start Game
INFO("%s", "Starting Game...");
#ifdef __ARM_ARCH
// Create Arguments List
char *new_argv[argc + 1];
for (int i = 1; i <= argc; i++) {
new_argv[i] = argv[i];
}
new_argv[0] = NULL; // Updated By safe_execvpe()
// Run
safe_execvpe_relative_to_binary(MCPI_NAME, new_argv, environ);
#else
// Use Static QEMU So It Isn't Affected By LD_* Variables
#define QEMU_NAME "qemu-arm-static"
// Use Correct LibC
setenv("QEMU_LD_PREFIX", "/usr/arm-linux-gnueabihf", 1);
INFO("Starting Game...");
// Get Binary Directory
binary_directory = get_binary_directory();
// Create Full Path
char *full_path = NULL;
safe_asprintf(&full_path, "%s/" MCPI_NAME, binary_directory);
// Free Binary Directory
free(binary_directory);
// Arguments
int argv_start = 1; // argv = &new_args[argv_start]
const char *new_args[argv_start /* 1 Potential Prefix Argument (QEMU) */ + argc + 1 /* NULL-Terminator */]; //
// Create Arguments List
char *new_argv[argc + 2];
for (int i = 1; i <= argc; i++) {
new_argv[i + 1] = argv[i];
// Copy Existing Arguments
for (int i = 1; i < argc; i++) {
new_args[i + argv_start] = argv[i];
}
new_argv[0] = NULL; // Updated By safe_execvpe()
new_argv[1] = full_path; // Path To MCPI
// Run
safe_execvpe(QEMU_NAME, new_argv, environ);
// NULL-Terminator
new_args[argv_start + argc] = NULL;
// Set Executable Argument
new_args[argv_start] = new_mcpi_exe_path;
// Non-ARM Systems Need QEMU
#ifndef __ARM_ARCH
argv_start--;
new_args[argv_start] = QEMU_BINARY;
#endif
// Setup Environment
setup_exec_environment(1);
// Pass LD_* Variables Through QEMU
#ifndef __ARM_ARCH
char *qemu_set_env = NULL;
#define pass_variable_through_qemu(name) string_append(&qemu_set_env, "%s%s=%s", qemu_set_env == NULL ? "" : ",", name, getenv(name));
for_each_special_environmental_variable(pass_variable_through_qemu);
set_and_print_env("QEMU_SET_ENV", qemu_set_env);
free(qemu_set_env);
// Treat QEMU Itself As A Native Component
setup_exec_environment(0);
#endif
// Run
const char **new_argv = &new_args[argv_start];
safe_execvpe(new_argv, (const char *const *) environ);
}

View File

@ -4,6 +4,7 @@
extern "C" {
#endif
void pre_bootstrap(int argc, char *argv[]);
void bootstrap(int argc, char *argv[]);
#ifdef __cplusplus

View File

@ -0,0 +1,44 @@
FALSE Full Touch GUI
TRUE Fix Bow & Arrow
TRUE Fix Attacking
FALSE Force Mob Spawning
TRUE Disable Autojump By Default
TRUE Display Nametags By Default
TRUE Fix Sign Placement
TRUE Show Block Outlines
FALSE Expand Creative Inventory
FALSE Remove Creative Mode Restrictions
TRUE Animated Water
TRUE Remove Invalid Item Background
TRUE Disable "gui_blocks" Atlas
FALSE 3D Anaglyph
TRUE Fix Camera Rendering
TRUE Implement Chat
FALSE Hide Chat Messages
TRUE Implement Death Messages
TRUE Implement Game-Mode Switching
TRUE Allow Joining Survival Servers
TRUE Miscellaneous Input Fixes
TRUE Bind "Q" Key To Item Dropping
TRUE Bind Common Toggleable Options To Function Keys
TRUE Render Selected Item Text
TRUE External Server Support
TRUE Load Language Files
TRUE Implement Sound Engine
TRUE Close Current Screen On Death
FALSE Disable Raw Mouse Motion (Not Recommended)
TRUE Fix Furnace Not Checking Item Auxiliary
TRUE Improved Cursor Rendering
TRUE Disable V-Sync
TRUE Fix Options Screen
TRUE Force Touch GUI Inventory
TRUE Fix Pause Menu
TRUE Improved Title Background
TRUE Force Touch GUI Button Behavior
TRUE Improved Button Hover Behavior
TRUE Implement Create World Dialog
FALSE Remove Forced GUI Lag (Can Break Joining Servers)
TRUE Add Buckets
TRUE Classic HUD
TRUE Translucent Toolbar
FALSE Force EGL

View File

@ -1,84 +1,84 @@
#include <fstream>
#include <sstream>
#include <cstring>
#include <cerrno>
#include <sys/wait.h>
#include <sys/stat.h>
#include <vector>
#include <functional>
#include <algorithm>
#include <libreborn/libreborn.h>
#include "../bootstrap.h"
// Strip Feature Flag Default
static std::string strip_feature_flag_default(std::string flag, bool *default_ret) {
// Valid Values
std::string true_str = "TRUE ";
std::string false_str = "FALSE ";
// Test
if (flag.rfind(true_str, 0) == 0) {
// Enabled By Default
if (default_ret != NULL) {
*default_ret = true;
}
return flag.substr(true_str.length(), std::string::npos);
} else if (flag.rfind(false_str, 0) == 0) {
// Disabled By Default
if (default_ret != NULL) {
*default_ret = false;
}
return flag.substr(false_str.length(), std::string::npos);
} else {
// Invalid
ERR("Invalid Feature Flag Default");
}
}
// Load Available Feature Flags
extern unsigned char available_feature_flags[];
extern size_t available_feature_flags_len;
static void load_available_feature_flags(std::function<void(std::string)> callback) {
// Get Path
char *binary_directory = get_binary_directory();
std::string path = std::string(binary_directory) + "/available-feature-flags";
free(binary_directory);
// Load File
std::ifstream stream(path);
if (stream && stream.good()) {
std::string data(available_feature_flags, available_feature_flags + available_feature_flags_len);
std::stringstream stream(data);
// Store Lines
std::vector<std::string> lines;
// Read File
{
std::string line;
while (std::getline(stream, line)) {
if (line.length() > 0) {
// Verify Line
if (line.find('|') == std::string::npos) {
callback(line);
lines.push_back(line);
} else {
// Invalid Line
ERR("%s", "Feature Flag Contains Invalid '|'");
ERR("Feature Flag Contains Invalid '|'");
}
}
}
stream.close();
} else {
ERR("%s", "Unable To Load Available Feature Flags");
}
// Sort
std::sort(lines.begin(), lines.end(), [](std::string a, std::string b) {
// Strip Defaults
std::string stripped_a = strip_feature_flag_default(a, NULL);
std::string stripped_b = strip_feature_flag_default(b, NULL);
// Sort
return stripped_a < stripped_b;
});
// Run Callbacks
for (std::string &line : lines) {
callback(line);
}
}
// Run Command And Get Output
static char *run_command(char *command[], int *return_code) {
// Store Output
int output_pipe[2];
safe_pipe2(output_pipe, 0);
// Run
pid_t ret = fork();
if (ret == -1) {
ERR("Unable To Run Command: %s", strerror(errno));
} else if (ret == 0) {
// Child Process
// Pipe stdout
dup2(output_pipe[1], STDOUT_FILENO);
close(output_pipe[0]);
close(output_pipe[1]);
// Run
safe_execvpe(command[0], command, environ);
} else {
// Parent Process
// Read stdout
close(output_pipe[1]);
char *output = NULL;
char c;
int bytes_read = 0;
while ((bytes_read = read(output_pipe[0], (void *) &c, 1)) > 0) {
string_append(&output, "%c", c);
}
close(output_pipe[0]);
// Get Return Code
int status;
waitpid(ret, &status, 0);
*return_code = WIFEXITED(status) ? WEXITSTATUS(status) : 1;
// Return
return output;
}
}
// Run Command And Set Environmental Variable
static void run_command_and_set_env(const char *env_name, char *command[]) {
static void run_command_and_set_env(const char *env_name, const char *command[]) {
// Only Run If Environmental Variable Is NULL
if (getenv(env_name) == NULL) {
// Run
@ -91,22 +91,28 @@ static void run_command_and_set_env(const char *env_name, char *command[]) {
output[length - 1] = '\0';
}
// Set
setenv(env_name, output, 1);
set_and_print_env(env_name, output);
// Free
free(output);
}
// Check Return Code
if (return_code != 0) {
ERR("%s", "Launch Interrupted");
if (!is_exit_status_success(return_code)) {
INFO("Launch Interrupted");
exit(EXIT_SUCCESS);
}
}
}
// Use Zenity To Set Environmental Variable
#define DIALOG_TITLE "Launcher"
static void run_zenity_and_set_env(const char *env_name, std::vector<std::string> command) {
// Create Full Command
std::vector<std::string> full_command;
full_command.push_back("zenity");
full_command.push_back("--class");
full_command.push_back("Minecraft: Pi Edition: Reborn");
full_command.push_back("--title");
full_command.push_back(DIALOG_TITLE);
full_command.push_back("--name");
full_command.push_back(MCPI_APP_ID);
full_command.insert(full_command.end(), command.begin(), command.end());
// Convert To C Array
const char *full_command_array[full_command.size() + 1];
@ -115,11 +121,34 @@ static void run_zenity_and_set_env(const char *env_name, std::vector<std::string
}
full_command_array[full_command.size()] = NULL;
// Run
run_command_and_set_env(env_name, (char **) full_command_array);
run_command_and_set_env(env_name, full_command_array);
}
// Set Variable If Not Already Set
static void set_env_if_unset(const char *env_name, std::function<std::string()> callback) {
if (getenv(env_name) == NULL) {
char *value = strdup(callback().c_str());
ALLOC_CHECK(value);
set_and_print_env(env_name, value);
free(value);
}
}
// Defaults
#define DEFAULT_USERNAME "StevePi"
#define DEFAULT_RENDER_DISTANCE "Short"
// Launch
#define LIST_DIALOG_SIZE "400"
int main(int argc, char *argv[]) {
// Don't Run As Root
if (getenv("_MCPI_SKIP_ROOT_CHECK") == NULL && (getuid() == 0 || geteuid() == 0)) {
ERR("Don't Run As Root");
}
// Pre-Bootstrap
pre_bootstrap(argc, argv);
// Print Features
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--print-available-feature-flags") == 0) {
@ -132,12 +161,42 @@ int main(int argc, char *argv[]) {
}
}
// --default
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--default") == 0) {
// Use Default Feature Flags
set_env_if_unset("MCPI_FEATURE_FLAGS", []() {
std::string feature_flags = "";
load_available_feature_flags([&feature_flags](std::string flag) {
bool default_value;
// Strip Default Value
std::string stripped_flag = strip_feature_flag_default(flag, &default_value);
// Specify Default Value
if (default_value) {
// Enabled By Default
feature_flags += stripped_flag + '|';
}
});
if (feature_flags.length() > 0 && feature_flags[feature_flags.length() - 1] == '|') {
feature_flags.pop_back();
}
return feature_flags;
});
set_env_if_unset("MCPI_RENDER_DISTANCE", []() {
return DEFAULT_RENDER_DISTANCE;
});
set_env_if_unset("MCPI_USERNAME", []() {
return DEFAULT_USERNAME;
});
break;
}
}
// Create ~/.minecraft-pi If Needed
// Minecraft Folder
{
char *minecraft_folder = NULL;
asprintf(&minecraft_folder, "%s/.minecraft-pi", getenv("HOME"));
ALLOC_CHECK(minecraft_folder);
safe_asprintf(&minecraft_folder, "%s/.minecraft-pi", getenv("HOME"));
{
// Check Minecraft Folder
struct stat obj;
@ -159,25 +218,27 @@ int main(int argc, char *argv[]) {
command.push_back("--list");
command.push_back("--checklist");
command.push_back("--width");
command.push_back("400");
command.push_back(LIST_DIALOG_SIZE);
command.push_back("--height");
command.push_back("400");
command.push_back(LIST_DIALOG_SIZE);
command.push_back("--column");
command.push_back("Enabled");
command.push_back("--column");
command.push_back("Feature");
load_available_feature_flags([&command](std::string line) {
if (line.rfind("TRUE ", 0) == 0) {
load_available_feature_flags([&command](std::string flag) {
bool default_value;
// Strip Default Value
std::string stripped_flag = strip_feature_flag_default(flag, &default_value);
// Specify Default Value
if (default_value) {
// Enabled By Default
command.push_back("TRUE");
command.push_back(line.substr(5, std::string::npos));
} else if (line.rfind("FALSE ", 0) == 0) {
} else {
// Disabled By Default
command.push_back("FALSE");
command.push_back(line.substr(6, std::string::npos));
} else {
ERR("%s", "Invalid Feature Flag Default");
}
// Specify Name
command.push_back(stripped_flag);
});
// Run
run_zenity_and_set_env("MCPI_FEATURE_FLAGS", command);
@ -188,23 +249,20 @@ int main(int argc, char *argv[]) {
command.push_back("--list");
command.push_back("--radiolist");
command.push_back("--width");
command.push_back("400");
command.push_back(LIST_DIALOG_SIZE);
command.push_back("--height");
command.push_back("400");
command.push_back(LIST_DIALOG_SIZE);
command.push_back("--text");
command.push_back("Minecraft Render Distance:");
command.push_back("Select Minecraft Render Distance:");
command.push_back("--column");
command.push_back("Selected");
command.push_back("--column");
command.push_back("Name");
command.push_back("FALSE");
command.push_back("Far");
command.push_back("FALSE");
command.push_back("Normal");
command.push_back("TRUE");
command.push_back("Short");
command.push_back("FALSE");
command.push_back("Tiny");
std::string render_distances[] = {"Far", "Normal", "Short", "Tiny"};
for (std::string &render_distance : render_distances) {
command.push_back(render_distance.compare(DEFAULT_RENDER_DISTANCE) == 0 ? "TRUE" : "FALSE");
command.push_back(render_distance);
}
// Run
run_zenity_and_set_env("MCPI_RENDER_DISTANCE", command);
}
@ -213,9 +271,9 @@ int main(int argc, char *argv[]) {
std::vector<std::string> command;
command.push_back("--entry");
command.push_back("--text");
command.push_back("Minecraft Username:");
command.push_back("Enter Minecraft Username:");
command.push_back("--entry-text");
command.push_back("StevePi");
command.push_back(DEFAULT_USERNAME);
// Run
run_zenity_and_set_env("MCPI_USERNAME", command);
}

246
launcher/src/crash-report.c Normal file
View File

@ -0,0 +1,246 @@
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <signal.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <libreborn/libreborn.h>
#include "crash-report.h"
// Show Crash Report Dialog
#ifndef MCPI_HEADLESS_MODE
#define DIALOG_TITLE "Crash Report"
#define CRASH_REPORT_DIALOG_WIDTH "640"
#define CRASH_REPORT_DIALOG_HEIGHT "480"
static void show_report(const char *log_filename) {
const char *command[] = {
"zenity",
"--title", DIALOG_TITLE,
"--name", MCPI_APP_ID,
"--width", CRASH_REPORT_DIALOG_WIDTH,
"--height", CRASH_REPORT_DIALOG_HEIGHT,
"--text-info",
"--text", "Minecraft: Pi Edition: Reborn has crashed!\n\nNeed help? Consider asking on the <a href=\"https://discord.com/invite/aDqejQGMMy\">Discord server</a>!",
"--filename", log_filename,
"--no-wrap",
"--font", "Monospace",
NULL
};
free(run_command(command, NULL));
}
#endif
// Exit Handler
static void exit_handler(__attribute__((unused)) int signal) {
// Murder
murder_children();
}
// Setup
#define PIPE_READ 0
#define PIPE_WRITE 1
#define MCPI_LOGS_DIR "/tmp/.minecraft-pi-logs"
void setup_crash_report() {
// Store Output
int output_pipe[2];
safe_pipe2(output_pipe, 0);
int error_pipe[2];
safe_pipe2(error_pipe, 0);
int input_pipe[2];
safe_pipe2(input_pipe, 0);
// Fork
pid_t ret = fork();
if (ret == -1) {
ERR("Unable To Fork: %s", strerror(errno));
} else if (ret == 0) {
// Child Process
// Pipe stdio
dup2(output_pipe[PIPE_WRITE], STDOUT_FILENO);
close(output_pipe[PIPE_READ]);
close(output_pipe[PIPE_WRITE]);
dup2(error_pipe[PIPE_WRITE], STDERR_FILENO);
close(error_pipe[PIPE_READ]);
close(error_pipe[PIPE_WRITE]);
dup2(input_pipe[PIPE_READ], STDIN_FILENO);
close(input_pipe[PIPE_READ]);
close(input_pipe[PIPE_WRITE]);
// Create New Process Group
setpgid(0, 0);
// Continue Execution
} else {
// Parent Process
track_child(ret);
// Install Signal Handlers
struct sigaction act_sigint;
memset((void *) &act_sigint, 0, sizeof (struct sigaction));
act_sigint.sa_flags = SA_RESTART;
act_sigint.sa_handler = &exit_handler;
sigaction(SIGINT, &act_sigint, NULL);
struct sigaction act_sigterm;
memset((void *) &act_sigterm, 0, sizeof (struct sigaction));
act_sigterm.sa_flags = SA_RESTART;
act_sigterm.sa_handler = &exit_handler;
sigaction(SIGTERM, &act_sigterm, NULL);
// Close Unneeded File Descriptors
close(output_pipe[PIPE_WRITE]);
close(error_pipe[PIPE_WRITE]);
close(input_pipe[PIPE_READ]);
// Setup Logging
#define BUFFER_SIZE 1024
char buf[BUFFER_SIZE];
// Ensure Temporary Directory
{
// Check If It Exists
struct stat tmp_stat;
int exists = stat(MCPI_LOGS_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode);
if (!exists) {
// Doesn't Exist
if (mkdir(MCPI_LOGS_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
ERR("Unable To Create Temporary Folder: %s", strerror(errno));
}
}
}
// Create Temporary File
char log_filename[] = MCPI_LOGS_DIR "/XXXXXX";
int log_file_fd = mkstemp(log_filename);
if (log_file_fd == -1) {
ERR("Unable To Create Log File: %s", strerror(errno));
}
// Setup Polling
int number_fds = 3;
struct pollfd poll_fds[number_fds];
poll_fds[0].fd = output_pipe[PIPE_READ];
poll_fds[1].fd = error_pipe[PIPE_READ];
poll_fds[2].fd = STDIN_FILENO;
for (int i = 0; i < number_fds; i++) {
poll_fds[i].events = POLLIN;
}
// Poll Data
int number_open_fds = number_fds;
while (number_open_fds > 0) {
int poll_ret = poll(poll_fds, number_fds, -1);
if (poll_ret == -1) {
if (errno == EINTR) {
continue;
} else {
ERR("Unable To Poll Data: %s", strerror(errno));
}
}
// Handle Data
for (int i = 0; i < number_fds; i++) {
if (poll_fds[i].revents != 0) {
if (poll_fds[i].revents & POLLIN) {
if (poll_fds[i].fd == STDIN_FILENO) {
// Data Available From stdin
int bytes_available;
if (ioctl(fileno(stdin), FIONREAD, &bytes_available) == -1) {
bytes_available = 0;
}
// Read
ssize_t bytes_read = read(poll_fds[i].fd, (void *) buf, BUFFER_SIZE);
if (bytes_read == -1) {
ERR("Unable To Read Log Data: %s", strerror(errno));
}
// Write To Child
if (write(input_pipe[PIPE_WRITE], (void *) buf, bytes_read) == -1) {
ERR("Unable To Write Input To Child: %s", strerror(errno));
}
} else {
// Data Available From Child's stdout/stderr
ssize_t bytes_read = read(poll_fds[i].fd, (void *) buf, BUFFER_SIZE - 1 /* Account For NULL-Terminator */);
if (bytes_read == -1) {
ERR("Unable To Read Log Data: %s", strerror(errno));
}
// Print To Terminal
buf[bytes_read] = '\0';
fprintf(i == 0 ? stdout : stderr, "%s", buf);
// Write To log
if (write(log_file_fd, (void *) buf, bytes_read) == -1) {
ERR("Unable To Write Log Data: %s", strerror(errno));
}
}
} else {
// File Descriptor No Longer Accessible
if (poll_fds[i].events != 0 && close(poll_fds[i].fd) == -1) {
ERR("Unable To Close File Descriptor: %s", strerror(errno));
}
poll_fds[i].events = 0;
number_open_fds--;
}
}
}
}
// Close Input Pipe
close(input_pipe[PIPE_WRITE]);
// Get Return Code
int status;
waitpid(ret, &status, 0);
untrack_child(ret);
// Check If Is Crash
int is_crash = !is_exit_status_success(status);
// Log Exit Code To log If Crash
if (is_crash) {
// Create Exit Code Log Line
char *exit_status = NULL;
get_exit_status_string(status, &exit_status);
char *exit_code_line = NULL;
safe_asprintf(&exit_code_line, "[CRASH]: Terminated%s\n", exit_status);
free(exit_status);
// Print Exit Code Log Line
fprintf(stderr, "%s", exit_code_line);
// Write Exit Code Log Line
if (write(log_file_fd, (void *) exit_code_line, strlen(exit_code_line)) == -1) {
ERR("Unable To Write Exit Code To Log: %s", strerror(errno));
}
// Free Exit Code Log Line
free(exit_code_line);
}
// Close Log File FD
if (close(log_file_fd) == -1) {
ERR("Unable To Close Log File Descriptor: %s", strerror(errno));
}
// Show Crash Log
#ifndef MCPI_HEADLESS_MODE
if (is_crash) {
show_report(log_filename);
}
#endif
// Delete Log File
if (unlink(log_filename) == -1) {
ERR("Unable To Delete Log File: %s", strerror(errno));
}
// Exit
exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
}
}

View File

@ -4,7 +4,7 @@
extern "C" {
#endif
int feature_has(const char *name, int server_default);
void setup_crash_report();
#ifdef __cplusplus
}

View File

@ -1,45 +0,0 @@
#include <unistd.h>
#include <string>
#include <cstring>
#include <cstdio>
#include <libreborn/libreborn.h>
#include "ldconfig.h"
char *get_full_library_search_path() {
std::string output;
// Run
FILE *file = popen("ldconfig -NXv 2> /dev/null", "r");
// Read
int running = 1;
while (running) {
char *line = NULL;
size_t length = 0;
if (getline(&line, &length, file) != -1) {
// Convert to C++ String
std::string str(line);
// Remove Newline
if (str.size() > 0 && str[str.size() - 1] == '\n') {
str.pop_back();
}
// Interpret
if (str.size() >= 2 && str[0] != '\t' && str[str.size() - 1] == ':') {
output.append(str);
}
} else {
running = 0;
}
free(line);
}
// Remove Colon
if (output.size() > 0 && output[output.size() - 1] == ':') {
output.pop_back();
}
// Close Process
pclose(file);
// Return
char *output_str = strdup(output.c_str());
ALLOC_CHECK(output_str);
return output_str;
}

136
launcher/src/patchelf.c Normal file
View File

@ -0,0 +1,136 @@
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>
#include <libreborn/libreborn.h>
#include "bootstrap.h"
#include "patchelf.h"
// Duplicate MCPI Executable Into /tmp
static void duplicate_mcpi_executable(const char *original_path, char *new_path) {
// Ensure Temporary Directory
{
// Check If It Exists
struct stat tmp_stat;
int exists = stat(MCPI_PATCHED_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode);
if (!exists) {
// Doesn't Exist
if (mkdir(MCPI_PATCHED_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
ERR("Unable To Create Temporary Folder: %s", strerror(errno));
}
}
}
// Generate New File
int new_file_fd = mkstemp(new_path);
if (new_file_fd == -1) {
ERR("Unable To Create Temporary File: %s", strerror(errno));
}
FILE *new_file = fdopen(new_file_fd, "wb");
if (new_file == NULL) {
ERR("Unable To Open Temporary File: %s", strerror(errno));
}
// Copy Original File
{
// Open Original File
FILE *original_file = fopen(original_path, "rb");
if (original_file == NULL) {
ERR("Unable To Open File: %s", original_path);
}
// Copy
#define BUFFER_SIZE 1024
char buf[BUFFER_SIZE];
size_t bytes_read = 0;
while ((bytes_read = fread((void *) buf, 1, BUFFER_SIZE, original_file)) > 0) {
fwrite((void *) buf, 1, bytes_read, new_file);
if (ferror(new_file) != 0) {
ERR("Unable To Write File: %s", new_path);
}
}
if (ferror(original_file) != 0) {
ERR("Unable To Read File: %s", original_path);
}
// Close Original File
fclose(original_file);
}
// Close New File
fclose(new_file);
close(new_file_fd);
}
// Fix MCPI Dependencies
#define patch_mcpi_elf_dependencies_with_extra_patchelf_args(...) \
({ \
const char *const _macro_command[] = { \
"patchelf", \
##__VA_ARGS__, \
"--remove-needed", "libbcm_host.so", \
"--remove-needed", "libX11.so.6", \
"--remove-needed", "libEGL.so", \
"--remove-needed", "libGLESv2.so", \
"--remove-needed", "libSDL-1.2.so.0", \
"--add-needed", "libmedia-layer-core.so", \
new_path, \
NULL \
}; \
int _macro_return_code = 0; \
char *_macro_output = run_command(_macro_command, &_macro_return_code); \
if (_macro_output != NULL) { \
free(_macro_output); \
} \
_macro_return_code; \
})
void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker) {
// Duplicate MCPI executable into /tmp so it can be modified.
duplicate_mcpi_executable(original_path, new_path);
// Run patchelf
int return_code;
if (linker == NULL) {
return_code = patch_mcpi_elf_dependencies_with_extra_patchelf_args();
} else {
return_code = patch_mcpi_elf_dependencies_with_extra_patchelf_args("--set-interpreter", linker);
}
if (!is_exit_status_success(return_code)) {
char *exit_status_line = NULL;
get_exit_status_string(return_code, &exit_status_line);
ERR("patchelf Failed%s", exit_status_line);
}
// Fix Permissions
if (chmod(new_path, S_IRUSR | S_IXUSR) != 0) {
ERR("Unable To Set File Permissions: %s: %s", new_path, strerror(errno));
}
}
// Get Interpreter
char *patch_get_interpreter(const char *file) {
// Run
const char *const command[] = {
"patchelf",
"--print-interpreter",
file,
NULL
};
int return_code;
char *output = run_command(command, &return_code);
if (!is_exit_status_success(return_code)) {
char *exit_status_line = NULL;
get_exit_status_string(return_code, &exit_status_line);
ERR("patchelf Failed%s", exit_status_line);
}
if (output != NULL) {
// Trim
int length = strlen(output);
if (output[length - 1] == '\n') {
output[length - 1] = '\0';
}
}
// Return
return output;
}

14
launcher/src/patchelf.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#define MCPI_PATCHED_DIR "/tmp/.minecraft-pi-patched"
void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker);
char *patch_get_interpreter(const char *file);
#ifdef __cplusplus
}
#endif

View File

@ -1,6 +1,19 @@
#include <stdlib.h>
#include <unistd.h>
#include <libreborn/libreborn.h>
#include "../bootstrap.h"
int main(int argc, char *argv[]) {
// Pre-Bootstrap
pre_bootstrap(argc, argv);
// Set Home To Current Directory, So World Data Is Stored There
char *launch_directory = getcwd(NULL, 0);
set_and_print_env("HOME", launch_directory);
free(launch_directory);
// Bootstrap
bootstrap(argc, argv);
}

View File

@ -1,11 +1,34 @@
project(libreborn)
add_library(reborn-headers INTERFACE)
target_include_directories(reborn-headers INTERFACE include)
# Config
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn")
configure_file(include/libreborn/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn/config.h" ESCAPE_QUOTES @ONLY)
# Util
add_library(reborn-util SHARED src/util/elf.c src/util/exec.c src/util/string.c src/util/util.c)
target_include_directories(
reborn-util
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:${MCPI_SDK_INCLUDE_DIR}/libreborn>"
)
# Install
install(TARGETS reborn-util DESTINATION "${MCPI_LIB_DIR}")
# SDK
if(BUILD_ARM_COMPONENTS)
add_library(reborn SHARED src/libreborn.c)
target_link_libraries(reborn dl reborn-headers)
# Install
install(TARGETS reborn DESTINATION "${MCPI_LIB_DIR}")
install(TARGETS reborn-util EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
install(DIRECTORY "include/" DESTINATION "${MCPI_SDK_INCLUDE_DIR}/libreborn")
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/" DESTINATION "${MCPI_SDK_INCLUDE_DIR}/libreborn")
endif()
# Patch
if(BUILD_ARM_COMPONENTS)
add_library(reborn-patch SHARED src/patch/patch.c)
target_link_libraries(reborn-patch dl pthread reborn-util)
target_compile_definitions(reborn-patch PUBLIC -DREBORN_HAS_PATCH_CODE)
# Install
install(TARGETS reborn-patch DESTINATION "${MCPI_LIB_DIR}")
# SDK
install(TARGETS reborn-patch EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
endif()

View File

@ -0,0 +1,11 @@
#pragma once
#cmakedefine MCPI_SERVER_MODE
#cmakedefine MCPI_HEADLESS_MODE
#cmakedefine MCPI_IS_APPIMAGE_BUILD
#cmakedefine MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
#cmakedefine MCPI_USE_GLES1_COMPATIBILITY_LAYER
#cmakedefine MCPI_APP_TITLE "@MCPI_APP_TITLE@"
#cmakedefine MCPI_APP_ID "@MCPI_APP_ID@"
#cmakedefine MCPI_VERSION "@MCPI_VERSION@"
#cmakedefine MCPI_SDK_DIR "@MCPI_SDK_DIR@"

View File

@ -1,67 +1,22 @@
#pragma once
#ifdef __arm__
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <elf.h>
#include <link.h>
#include "log.h"
#include "exec.h"
// Find And Iterate Over All .text Sections In Current Binary
typedef void (*text_section_callback_t)(void *section, Elf32_Word size, void *data);
static inline void iterate_text_sections(text_section_callback_t callback, void *data) {
// Load Main Binary
char *real_path = realpath("/proc/self/exe", NULL);
FILE *file_obj = fopen(real_path, "rb");
#ifdef __cplusplus
extern "C" {
#endif
// Verify Binary
if (!file_obj) {
ERR("Unable To Open Binary: %s", real_path);
}
// Find And Iterate Over All Segments In Current Binary
typedef void (*segment_callback_t)(ElfW(Addr) section, ElfW(Word) size, void *data);
void iterate_segments(segment_callback_t callback, void *data);
// Get File Size
fseek(file_obj, 0L, SEEK_END);
long int size = ftell(file_obj);
fseek(file_obj, 0L, SEEK_SET);
// Map File To Pointer
unsigned char *file_map = (unsigned char *) mmap(0, size, PROT_READ, MAP_PRIVATE, fileno(file_obj), 0);
// Parse ELF
Elf32_Ehdr *elf_header = (Elf32_Ehdr *) file_map;
Elf32_Shdr *elf_section_headers = (Elf32_Shdr *) (file_map + elf_header->e_shoff);
int elf_section_header_count = elf_header->e_shnum;
// Locate Section Names
Elf32_Shdr elf_strtab = elf_section_headers[elf_header->e_shstrndx];
unsigned char *elf_strtab_p = file_map + elf_strtab.sh_offset;
// Track .text Sections
int text_sections = 0;
// Iterate Sections
for (int i = 0; i < elf_section_header_count; ++i) {
Elf32_Shdr header = elf_section_headers[i];
char *name = (char *) (elf_strtab_p + header.sh_name);
// Check Section Type
if (strcmp(name, ".text") == 0) {
// .text Section
(*callback)((void *) header.sh_addr, header.sh_size, data);
text_sections++;
}
}
// Ensure At Least .text Section Was Scanned
if (text_sections < 1) {
ERR("Unable To Find .text Sectons On: %s", real_path);
}
// Free Binary Path
free(real_path);
// Unmap And Close File
munmap(file_map, size);
fclose(file_obj);
#ifdef __cplusplus
}
#endif // #ifdef __arm__
#endif

View File

@ -3,69 +3,47 @@
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#include "log.h"
#include "string.h"
#include "util.h"
#ifdef __cplusplus
extern "C" {
#endif
// Set Environmental Variable
void set_and_print_env(const char *name, const char *value);
// Safe execvpe()
__attribute__((noreturn)) static inline void safe_execvpe(const char *pathname, char *argv[], char *const envp[]) {
argv[0] = (char *) pathname;
int ret = execvpe(pathname, argv, envp);
if (ret == -1) {
ERR("Unable To Execute Program: %s: %s", pathname, strerror(errno));
} else {
ERR("%s", "Unknown execvpe() Error");
}
}
#define for_each_special_environmental_variable(handle) \
handle("LD_LIBRARY_PATH"); \
handle("GCONV_PATH"); \
handle("LD_PRELOAD");
void setup_exec_environment(int is_arm_component);
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]);
// Chop Off Last Component
void chop_last_component(char **str);
// Get Binary Directory (Remember To Free)
#define EXE_PATH "/proc/self/exe"
static inline char *get_binary_directory() {
// Get Path To Current Executable
// Get Symlink Path Size
struct stat sb;
if (lstat(EXE_PATH, &sb) == -1) {
ERR("Unable To Get " EXE_PATH " Symlink Size: %s", strerror(errno));
}
ssize_t path_size = sb.st_size;
if (sb.st_size <= 0) {
path_size = PATH_MAX;
}
char *exe = (char *) malloc(path_size + 1);
ALLOC_CHECK(exe);
// Read Link
ssize_t r = readlink(EXE_PATH, exe, path_size);
if (r < 0) {
ERR("Unable To Read " EXE_PATH " Symlink: %s", strerror(errno));
}
if (r > path_size) {
ERR("%s", "Size Of Symlink " EXE_PATH " Changed");
}
exe[r + 1] = '\0';
char *get_binary_directory();
// Chop Off Last Component
for (int i = r; i >= 0; i--) {
if (exe[i] == '/') {
exe[i] = '\0';
break;
}
}
// Run Command And Get Output
char *run_command(const char *const command[], int *exit_status);
#define is_exit_status_success(status) (WIFEXITED(status) && WEXITSTATUS(status) == 0)
// Return
return exe;
}
// Safe execvpe() Relative To Binary
__attribute__((noreturn)) static inline void safe_execvpe_relative_to_binary(const char *pathname, char *argv[], char *const envp[]) {
// Get Binary Directory
char *binary_directory = get_binary_directory();
// Create Full Path
char *full_path = NULL;
safe_asprintf(&full_path, "%s/%s", binary_directory, pathname);
// Free Binary Directory
free(binary_directory);
// Run
safe_execvpe(full_path, argv, envp);
// Get Exit Status String
void get_exit_status_string(int status, char **out);
// Track Children
void track_child(pid_t pid);
void untrack_child(pid_t pid);
void murder_children();
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,10 @@
#pragma once
// Minecraft Pi Game Data Root
#ifndef MCPI_SERVER_MODE
// Store Game Data In "~/.minecraft-pi" Instead Of "~/.minecraft" To Avoid Conflicts
#define HOME_SUBDIRECTORY_FOR_GAME_DATA "/.minecraft-pi"
#else
// Store Game Data In $HOME Root (In Server Mode, $HOME Is Changed To The Launch Directory)
#define HOME_SUBDIRECTORY_FOR_GAME_DATA ""
#endif

View File

@ -1,36 +1,10 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <libreborn/config.h>
#include "log.h"
#include "util.h"
#include "string.h"
#include "exec.h"
#include "elf.h"
#ifdef __arm__
// Patching Functions
void _overwrite_call(const char *file, int line, void *start, void *target);
#define overwrite_call(start, target) _overwrite_call(__FILE__, __LINE__, start, target);
void _overwrite_calls(const char *file, int line, void *start, void *target);
#define overwrite_calls(start, target) _overwrite_calls(__FILE__, __LINE__, start, target);
void _overwrite(const char *file, int line, void *start, void *target);
#define overwrite(start, target) _overwrite(__FILE__, __LINE__, start, target);
void _patch(const char *file, int line, void *start, unsigned char patch[]);
#define patch(start, patch) _patch(__FILE__, __LINE__, start, patch);
void _patch_address(const char *file, int line, void *start, void *target);
#define patch_address(start, target) _patch_address(__FILE__, __LINE__, start, target);
#endif // #ifdef __arm__
#ifdef __cplusplus
}
#endif
#include "home.h"
#include "patch.h"

View File

@ -4,6 +4,8 @@
#include <stdlib.h>
// Logging
#define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", __VA_ARGS__); }
#define WARN(format, ...) { fprintf(stderr, "[WARN]: " format "\n", __VA_ARGS__); }
#define ERR(format, ...) { fprintf(stderr, "[ERR]: " format "\n", __VA_ARGS__); exit(EXIT_FAILURE); }
#define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", ##__VA_ARGS__); }
#define WARN(format, ...) { fprintf(stderr, "[WARN]: " format "\n", ##__VA_ARGS__); }
#define DEBUG(format, ...) { const char *debug = getenv("MCPI_DEBUG"); if (debug != NULL) { fprintf(stderr, "[DEBUG]: " format "\n", ##__VA_ARGS__); } }
#define ERR(format, ...) { fprintf(stderr, "[ERR]: (%s:%i): " format "\n", __FILE__, __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); }
#define IMPOSSIBLE() ERR("This Should Never Be Called")

View File

@ -1,535 +0,0 @@
#pragma once
#include <stdint.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
// bool In C
#ifndef __cplusplus
typedef uint32_t bool;
#endif
// Globals
typedef void (*renderCursor_t)(float x, float y, unsigned char *minecraft);
static renderCursor_t renderCursor = (renderCursor_t) 0x480c4;
static char **default_path = (char **) 0xe264; // /.minecraft/
static char **default_username = (char **) 0x18fd4; // StevePi
static char **minecraft_pi_version = (char **) 0x39d94; // v0.1.1 alpha
static unsigned char **Item_flintAndSteel = (unsigned char **) 0x17ba70;
static unsigned char **Item_snowball = (unsigned char **) 0x17bbb0;
static unsigned char **Item_shears = (unsigned char **) 0x17bbf0;
static unsigned char **Item_egg = (unsigned char **) 0x17bbd0;
static unsigned char **Item_dye_powder = (unsigned char **) 0x17bbe0;
static unsigned char **Item_camera = (unsigned char **) 0x17bc14;
static unsigned char **Tile_water = (unsigned char **) 0x181b3c;
static unsigned char **Tile_lava = (unsigned char **) 0x181cc8;
static unsigned char **Tile_calmWater = (unsigned char **) 0x181b40;
static unsigned char **Tile_calmLava = (unsigned char **) 0x181ccc;
static unsigned char **Tile_glowingObsidian = (unsigned char **) 0x181dcc;
static unsigned char **Tile_web = (unsigned char **) 0x181d08;
static unsigned char **Tile_topSnow = (unsigned char **) 0x181b30;
static unsigned char **Tile_ice = (unsigned char **) 0x181d80;
static unsigned char **Tile_invisible_bedrock = (unsigned char **) 0x181d94;
static unsigned char **Tile_leaves = (unsigned char **) 0x18120c;
static unsigned char **Tile_leaves_carried = (unsigned char **) 0x181dd8;
static unsigned char **Tile_grass = (unsigned char **) 0x181b14;
static unsigned char **Tile_grass_carried = (unsigned char **) 0x181dd4;
static float *InvGuiScale = (float *) 0x135d98;
// Tile
static uint32_t Tile_id_property_offset = 0x8;
// Structures
struct LevelSettings {
unsigned long seed;
int32_t game_type;
};
struct RakNet_RakNetGUID {
unsigned char data[10];
};
struct RakNet_SystemAddress {
unsigned char data[20];
};
// GameMode
typedef void (*GameMode_releaseUsingItem_t)(unsigned char *game_mode, unsigned char *player);
static uint32_t GameMode_releaseUsingItem_vtable_offset = 0x5c;
// Minecraft
typedef void (*Minecraft_init_t)(unsigned char *minecraft);
static Minecraft_init_t Minecraft_init = (Minecraft_init_t) 0x1700c;
typedef void (*Minecraft_tickInput_t)(unsigned char *minecraft);
static Minecraft_tickInput_t Minecraft_tickInput = (Minecraft_tickInput_t) 0x15ffc;
typedef void (*Minecraft_setIsCreativeMode_t)(unsigned char *, int32_t);
static Minecraft_setIsCreativeMode_t Minecraft_setIsCreativeMode = (Minecraft_setIsCreativeMode_t) 0x16ec4;
typedef int32_t (*Minecraft_isTouchscreen_t)(unsigned char *minecraft);
static Minecraft_isTouchscreen_t Minecraft_isTouchscreen = (Minecraft_isTouchscreen_t) 0x1639c;
typedef void (*Minecraft_setScreen_t)(unsigned char *minecraft, unsigned char *screen);
static Minecraft_setScreen_t Minecraft_setScreen = (Minecraft_setScreen_t) 0x15d6c;
typedef void (*Minecraft_tick_t)(unsigned char *minecraft, int32_t param_1, int32_t param_2);
static Minecraft_tick_t Minecraft_tick = (Minecraft_tick_t) 0x16934;
typedef void (*Minecraft_update_t)(unsigned char *minecraft);
static Minecraft_update_t Minecraft_update = (Minecraft_update_t) 0x16b74;
typedef void (*Minecraft_hostMultiplayer_t)(unsigned char *minecraft, int32_t port);
static Minecraft_hostMultiplayer_t Minecraft_hostMultiplayer = (Minecraft_hostMultiplayer_t) 0x16664;
typedef const char *(*Minecraft_getProgressMessage_t)(unsigned char *minecraft);
static Minecraft_getProgressMessage_t Minecraft_getProgressMessage = (Minecraft_getProgressMessage_t) 0x16e58;
typedef uint32_t (*Minecraft_isLevelGenerated_t)(unsigned char *minecraft);
static Minecraft_isLevelGenerated_t Minecraft_isLevelGenerated = (Minecraft_isLevelGenerated_t) 0x16e6c;
typedef bool (*Minecraft_isCreativeMode_t)(unsigned char *minecraft);
static Minecraft_isCreativeMode_t Minecraft_isCreativeMode = (Minecraft_isCreativeMode_t) 0x17270;
typedef void (*Minecraft_releaseMouse_t)(unsigned char *minecraft);
static Minecraft_releaseMouse_t Minecraft_releaseMouse = (Minecraft_releaseMouse_t) 0x15d30;
typedef void (*Minecraft_grabMouse_t)(unsigned char *minecraft);
static Minecraft_grabMouse_t Minecraft_grabMouse = (Minecraft_grabMouse_t) 0x15d10;
typedef void (*Minecraft_leaveGame_t)(unsigned char *minecraft, bool save_remote_level);
static Minecraft_leaveGame_t Minecraft_leaveGame = (Minecraft_leaveGame_t) 0x15ea0;
typedef int (*Minecraft_handleBack_t)(unsigned char *minecraft, bool do_nothing);
static uint32_t Minecraft_handleBack_vtable_offset = 0x34;
static uint32_t Minecraft_screen_width_property_offset = 0x20; // int32_t
static uint32_t Minecraft_network_handler_property_offset = 0x174; // NetEventCallback *
static uint32_t Minecraft_rak_net_instance_property_offset = 0x170; // RakNetInstance *
static uint32_t Minecraft_level_property_offset = 0x188; // Level *
static uint32_t Minecraft_textures_property_offset = 0x164; // Textures *
static uint32_t Minecraft_game_mode_property_offset = 0x160; // GameMode *
static uint32_t Minecraft_player_property_offset = 0x18c; // LocalPlayer *
static uint32_t Minecraft_options_property_offset = 0x3c; // Options
static uint32_t Minecraft_hit_result_property_offset = 0xc38; // HitResult
static uint32_t Minecraft_progress_property_offset = 0xc60; // int32_t
static uint32_t Minecraft_command_server_property_offset = 0xcc0; // CommandServer *
static uint32_t Minecraft_screen_property_offset = 0xc10; // Screen *
static uint32_t Minecraft_gui_property_offset = 0x198; // Gui
// GameRenderer
typedef void (*GameRenderer_render_t)(unsigned char *game_renderer, float param_1);
static GameRenderer_render_t GameRenderer_render = (GameRenderer_render_t) 0x4a338;
static uint32_t GameRenderer_minecraft_property_offset = 0x4; // Minecraft *
// Mouse
typedef int (*Mouse_get_t)();
static Mouse_get_t Mouse_getX = (Mouse_get_t) 0x1385c;
static Mouse_get_t Mouse_getY = (Mouse_get_t) 0x1386c;
// CommandServer
static uint32_t CommandServer_minecraft_property_offset = 0x18; // Minecraft *
// ServerLevel
#define SERVER_LEVEL_SIZE 0xb80
// Packet
typedef void (*Packet_read_t)(unsigned char *packet, unsigned char *bit_stream);
// LoginPacket
static Packet_read_t LoginPacket_read = (Packet_read_t) 0x6e5f8;
static void *LoginPacket_read_vtable_addr = (void *) 0x108dcc;
static uint32_t LoginPacket_username_property_offset = 0xc; // RakString
// ChatPacket
static uint32_t ChatPacket_message_property_offset = 0xc; // char *
// HitResult
static uint32_t HitResult_type_property_offset = 0x0;
// Options
static uint32_t Options_fancy_graphics_property_offset = 0x17; // unsigned char / bool
static uint32_t Options_split_controls_property_offset = 0x105; // int32_t
static uint32_t Options_peaceful_mode_property_offset = 0xe8; // unsigned char / bool
static uint32_t Options_3d_anaglyph_property_offset = 0x15; // unsigned char / bool
static uint32_t Options_ambient_occlusion_property_offset = 0x18; // unsigned char / bool
static uint32_t Options_hide_gui_property_offset = 0xec; // unsigned char / bool
static uint32_t Options_third_person_property_offset = 0xed; // unsigned char / bool
static uint32_t Options_render_distance_property_offset = 0x10; // int32_t
// MouseBuildInput
typedef int32_t (*MouseBuildInput_tickBuild_t)(unsigned char *mouse_build_input, unsigned char *player, uint32_t *build_action_intention_return);
static MouseBuildInput_tickBuild_t MouseBuildInput_tickBuild = (MouseBuildInput_tickBuild_t) 0x17c98;
static void *MouseBuildInput_tickBuild_vtable_addr = (void *) 0x102564;
// ItemInstance
typedef struct {
int32_t count;
int32_t id;
int32_t auxilary;
} ItemInstance;
typedef ItemInstance *(*ItemInstance_constructor_t)(ItemInstance *item_instance, unsigned char *item);
static ItemInstance_constructor_t ItemInstance_constructor_item = (ItemInstance_constructor_t) 0x9992c;
static ItemInstance_constructor_t ItemInstance_constructor_tile = (ItemInstance_constructor_t) 0x998e4;
typedef ItemInstance *(*ItemInstance_constructor_extra_t)(ItemInstance *item_instance, unsigned char *item, int32_t count, int32_t auxilary);
static ItemInstance_constructor_extra_t ItemInstance_constructor_tile_extra = (ItemInstance_constructor_extra_t) 0x99918;
static ItemInstance_constructor_extra_t ItemInstance_constructor_item_extra = (ItemInstance_constructor_extra_t) 0x99960;
// Player
typedef int (*Player_isUsingItem_t)(unsigned char *player);
static Player_isUsingItem_t Player_isUsingItem = (Player_isUsingItem_t) 0x8f15c;
typedef void (*Player_drop_t)(unsigned char *player, ItemInstance *item_instance, bool is_death);
static uint32_t Player_drop_vtable_offset = 0x208;
static uint32_t Player_username_property_offset = 0xbf4; // char *
static uint32_t Player_inventory_property_offset = 0xbe0; // Inventory *
// Entity
typedef void (*Entity_die_t)(unsigned char *entity, unsigned char *cause);
static uint32_t Entity_die_vtable_offset = 0x130;
// Mob
typedef void (*Mob_actuallyHurt_t)(unsigned char *entity, int32_t damage);
static Mob_actuallyHurt_t Mob_actuallyHurt = (Mob_actuallyHurt_t) 0x7f11c;
static uint32_t Mob_actuallyHurt_vtable_offset = 0x16c;
static uint32_t Mob_health_property_offset = 0xec; // int32_t
// LocalPlayer
static Mob_actuallyHurt_t LocalPlayer_actuallyHurt = (Mob_actuallyHurt_t) 0x44010;
static void *LocalPlayer_actuallyHurt_vtable_addr = (void *) 0x10639c;
static void *LocalPlayer_openTextEdit_vtable_addr = (void *) 0x106460;
static uint32_t LocalPlayer_minecraft_property_offset = 0xc90; // Minecraft *
// ServerPlayer
static void *ServerPlayer_actuallyHurt_vtable_addr = (void *) 0x109fa4;
static uint32_t ServerPlayer_minecraft_property_offset = 0xc8c; // Minecraft *
static uint32_t ServerPlayer_guid_property_offset = 0xc08; // RakNetGUID
// Gui
typedef void (*Gui_tick_t)(unsigned char *gui);
static Gui_tick_t Gui_tick = (Gui_tick_t) 0x27778;
typedef void (*Gui_handleClick_t)(unsigned char *gui, int32_t param_2, int32_t param_3, int32_t param_4);
static Gui_handleClick_t Gui_handleClick = (Gui_handleClick_t) 0x2599c;
typedef void (*Gui_renderOnSelectItemNameText_t)(unsigned char *gui, int32_t param_1, unsigned char *font, int32_t param_2);
static Gui_renderOnSelectItemNameText_t Gui_renderOnSelectItemNameText = (Gui_renderOnSelectItemNameText_t) 0x26aec;
typedef void (*Gui_renderChatMessages_t)(unsigned char *gui, int32_t param_1, uint32_t param_2, bool param_3, unsigned char *font);
static Gui_renderChatMessages_t Gui_renderChatMessages = (Gui_renderChatMessages_t) 0x273d8;
static uint32_t Gui_minecraft_property_offset = 0x9f4; // Minecraft *
static uint32_t Gui_selected_item_text_timer_property_offset = 0x9fc; // float
// Textures
typedef void (*Textures_tick_t)(unsigned char *textures, bool param_1);
static Textures_tick_t Textures_tick = (Textures_tick_t) 0x531c4;
// GameMode Constructors
#define CREATOR_MODE_SIZE 0x18
static void *CreatorMode = (void *) 0x1a044;
#define SURVIVAL_MODE_SIZE 0x24
static void *SurvivalMode = (void *) 0x1b7d8;
// LevelData
typedef uint32_t (*LevelData_getSpawnMobs_t)(unsigned char *level_data);
static LevelData_getSpawnMobs_t LevelData_getSpawnMobs = (LevelData_getSpawnMobs_t) 0xbabec;
// Level
typedef void (*Level_saveLevelData_t)(unsigned char *level);
static Level_saveLevelData_t Level_saveLevelData = (Level_saveLevelData_t) 0xa2e94;
static uint32_t Level_players_property_offset = 0x60; // std::vector<ServerPlayer *>
// TextEditScreen
#define TEXT_EDIT_SCREEN_SIZE 0xd0
typedef unsigned char *(*TextEditScreen_t)(unsigned char *text_edit_screen, unsigned char *sign);
static TextEditScreen_t TextEditScreen = (TextEditScreen_t) 0x3a840;
static void *TextEditScreen_updateEvents_vtable_addr = (void *) 0x10531c;
// ProgressScreen
#define PROGRESS_SCREEN_SIZE 0x4c
typedef void *(*ProgressScreen_t)(unsigned char *obj);
static ProgressScreen_t ProgressScreen = (ProgressScreen_t) 0x37044;
// OptionsScreen
static void *OptionsScreen_handleBackEvent_vtable_addr = (void *) 0x10499c;
// Screen
typedef void (*Screen_updateEvents_t)(unsigned char *screen);
static Screen_updateEvents_t Screen_updateEvents = (Screen_updateEvents_t) 0x28eb8;
typedef void (*Screen_keyboardNewChar_t)(unsigned char *screen, char key);
static uint32_t Screen_keyboardNewChar_vtable_offset = 0x70;
typedef void (*Screen_keyPressed_t)(unsigned char *screen, int32_t key);
static uint32_t Screen_keyPressed_vtable_offset = 0x6c;
typedef void (*Screen_tick_t)(unsigned char *screen);
typedef int32_t (*Screen_handleBackEvent_t)(unsigned char *screen, bool param_1);
static uint32_t Screen_minecraft_property_offset = 0x14; // Minecraft *
// SelectWorldScreen
static Screen_tick_t SelectWorldScreen_tick = (Screen_tick_t) 0x38a2c;
static void *SelectWorldScreen_tick_vtable_addr = (void *) 0x104f78;
static uint32_t SelectWorldScreen_should_create_world_property_offset = 0xfc; // bool
static uint32_t SelectWorldScreen_world_created_property_offset = 0xf9; // bool
// Touch::SelectWorldScreen
static Screen_tick_t Touch_SelectWorldScreen_tick = (Screen_tick_t) 0x3d96c;
static void *Touch_SelectWorldScreen_tick_vtable_addr = (void *) 0x105780;
static uint32_t Touch_SelectWorldScreen_should_create_world_property_offset = 0x154; // bool
static uint32_t Touch_SelectWorldScreen_world_created_property_offset = 0x151; // bool
// FillingContainer
typedef int32_t (*FillingContainer_addItem_t)(unsigned char *filling_container, ItemInstance *item_instance);
static FillingContainer_addItem_t FillingContainer_addItem = (FillingContainer_addItem_t) 0x92aa0;
typedef ItemInstance *(*FillingContainer_getItem_t)(unsigned char *filling_container, int32_t slot);
static uint32_t FillingContainer_getItem_vtable_offset = 0x8;
typedef void (*FillingContainer_setItem_t)(unsigned char *filling_container, int32_t slot, ItemInstance *item_instance);
static uint32_t FillingContainer_setItem_vtable_offset = 0xc;
typedef void (*FillingContainer_clearSlot_t)(unsigned char *filling_container, int32_t slot);
static FillingContainer_clearSlot_t FillingContainer_clearSlot = (FillingContainer_clearSlot_t) 0x922f8;
typedef void (*FillingContainer_release_t)(unsigned char *filling_container, int32_t slot);
static FillingContainer_release_t FillingContainer_release = (FillingContainer_release_t) 0x92058;
typedef void (*FillingContainer_compressLinkedSlotList_t)(unsigned char *filling_container, int32_t slot);
static FillingContainer_compressLinkedSlotList_t FillingContainer_compressLinkedSlotList = (FillingContainer_compressLinkedSlotList_t) 0x92280;
static uint32_t FillingContainer_linked_slots_property_offset = 0xc; // int32_t[]
static uint32_t FillingContainer_linked_slots_length_property_offset = 0x14; // int32_t
// RakNet::RakString
typedef void (*RakNet_RakString_Assign_t)(unsigned char *rak_string, const char *str);
static RakNet_RakString_Assign_t RakNet_RakString_Assign = (RakNet_RakString_Assign_t) 0xe9e34;
static uint32_t RakNet_RakString_sharedString_property_offset = 0x0; // RakNet::RakString::SharedString *
// RakNet::RakString::SharedString
static uint32_t RakNet_RakString_SharedString_c_str_property_offset = 0x10; // char *
// RakNetInstance
typedef void (*RakNetInstance_send_t)(unsigned char *rak_net_instance, unsigned char *packet);
static uint32_t RakNetInstance_send_vtable_offset = 0x38;
typedef uint32_t (*RakNetInstance_isServer_t)(unsigned char *rak_net_instance);
static uint32_t RakNetInstance_isServer_vtable_offset = 0x48;
typedef void (*RakNetInstance_pingForHosts_t)(unsigned char *rak_net_instance, int32_t base_port);
static RakNetInstance_pingForHosts_t RakNetInstance_pingForHosts = (RakNetInstance_pingForHosts_t) 0x73538;
static uint32_t RakNetInstance_pingForHosts_vtable_offset = 0x14;
static void *RakNetInstance_pingForHosts_vtable_addr = (void *) 0x109afc;
static uint32_t RakNetInstance_peer_property_offset = 0x4; // RakNet::RakPeer *
// RakNet::RakPeer
typedef struct RakNet_SystemAddress (*RakNet_RakPeer_GetSystemAddressFromGuid_t)(unsigned char *rak_peer, struct RakNet_RakNetGUID guid);
static uint32_t RakNet_RakPeer_GetSystemAddressFromGuid_vtable_offset = 0xd0;
typedef bool (*RakNet_RakPeer_IsBanned_t)(unsigned char *rak_peer, const char *ip);
static RakNet_RakPeer_IsBanned_t RakNet_RakPeer_IsBanned = (RakNet_RakPeer_IsBanned_t) 0xda3b4;
typedef bool (*RakNet_RakPeer_Ping_t)(unsigned char *rak_peer, const char *host, unsigned short remotePort, bool onlyReplyOnAcceptingConnections, uint32_t connectionSocketIndex);
static RakNet_RakPeer_Ping_t RakNet_RakPeer_Ping = (RakNet_RakPeer_Ping_t) 0xd9c2c;
// RakNet::SystemAddress
typedef char *(*RakNet_SystemAddress_ToString_t)(struct RakNet_SystemAddress *system_address, bool print_delimiter, char delimiter);
static RakNet_SystemAddress_ToString_t RakNet_SystemAddress_ToString = (RakNet_SystemAddress_ToString_t) 0xd6198;
// ServerSideNetworkHandler
typedef void (*ServerSideNetworkHandler_onDisconnect_t)(unsigned char *server_side_network_handler, unsigned char *guid);
static ServerSideNetworkHandler_onDisconnect_t ServerSideNetworkHandler_onDisconnect = (ServerSideNetworkHandler_onDisconnect_t) 0x75164;
static void *ServerSideNetworkHandler_onDisconnect_vtable_addr = (void *) 0x109bb0;
typedef unsigned char *(*ServerSideNetworkHandler_getPlayer_t)(unsigned char *server_side_network_handler, unsigned char *guid);
static ServerSideNetworkHandler_getPlayer_t ServerSideNetworkHandler_getPlayer = (ServerSideNetworkHandler_getPlayer_t) 0x75464;
typedef void (*ServerSideNetworkHandler_handle_t)(unsigned char *server_side_network_handler, unsigned char *rak_net_guid, unsigned char *packet);
static void *ServerSideNetworkHandler_handle_ChatPacket_vtable_addr = (void *) 0x109c60;
// Inventory
typedef void (*Inventory_selectSlot_t)(unsigned char *inventory, int32_t slot);
static Inventory_selectSlot_t Inventory_selectSlot = (Inventory_selectSlot_t) 0x8d13c;
static uint32_t Inventory_selectedSlot_property_offset = 0x28; // int32_t
// TripodCameraRenderer
#define TRIPOD_CAMERA_RENDERER_SIZE 0x193
typedef unsigned char *(*TripodCameraRenderer_t)(unsigned char *renderer);
static TripodCameraRenderer_t TripodCameraRenderer = (TripodCameraRenderer_t) 0x6583c;
// EntityRenderDispatcher
typedef unsigned char *(*EntityRenderDispatcher_t)(unsigned char *dispatcher);
static EntityRenderDispatcher_t EntityRenderDispatcher = (EntityRenderDispatcher_t) 0x6096c;
typedef void (*EntityRenderDispatcher_assign_t)(unsigned char *dispatcher, unsigned char entity_id, unsigned char *renderer);
static EntityRenderDispatcher_assign_t EntityRenderDispatcher_assign = (EntityRenderDispatcher_assign_t) 0x6094c;
// TileEntity
static uint32_t TileEntity_id_property_offset = 0x18; // int32_t
// ItemRenderer
typedef float (*ItemRenderer_renderGuiItem_t)(unsigned char *font, unsigned char *textures, ItemInstance *item_instance, float param_1, float param_2, bool param_3);
static ItemRenderer_renderGuiItem_t ItemRenderer_renderGuiItem = (ItemRenderer_renderGuiItem_t) 0x63e58;
typedef float (*ItemRenderer_renderGuiItemCorrect_t)(unsigned char *font, unsigned char *textures, ItemInstance *item_instance, int32_t param_1, int32_t param_2);
static ItemRenderer_renderGuiItemCorrect_t ItemRenderer_renderGuiItemCorrect = (ItemRenderer_renderGuiItemCorrect_t) 0x639a0;
// Tesselator
typedef void (*Tesselator_begin_t)(unsigned char *tesselator, int32_t mode);
static Tesselator_begin_t Tesselator_begin = (Tesselator_begin_t) 0x529d4;
typedef void (*Tesselator_colorABGR_t)(unsigned char *tesselator, int32_t color);
static Tesselator_colorABGR_t Tesselator_colorABGR = (Tesselator_colorABGR_t) 0x52b54;
typedef void (*Tesselator_color_t)(unsigned char *tesselator, int32_t r, int32_t g, int32_t b, int32_t a);
static Tesselator_color_t Tesselator_color = (Tesselator_color_t) 0x52a48;
// Method That Require C++ Types
#ifdef __cplusplus
#include <string>
// Structures
struct AppPlatform_readAssetFile_return_value {
char *data;
int32_t length;
};
struct ConnectedClient {
uint32_t sock;
std::string str;
long time;
};
// AppPlatform
typedef void (*AppPlatform_saveScreenshot_t)(unsigned char *app_platform, std::string const& path, int32_t width, int32_t height);
static void *AppPlatform_linux_saveScreenshot_vtable_addr = (void *) 0x102160;
typedef AppPlatform_readAssetFile_return_value (*AppPlatform_readAssetFile_t)(unsigned char *app_platform, std::string const& path);
static AppPlatform_readAssetFile_t AppPlatform_readAssetFile = (AppPlatform_readAssetFile_t) 0x12b10;
// Minecraft
typedef void (*Minecraft_selectLevel_t)(unsigned char *minecraft, std::string const& level_dir, std::string const& level_name, LevelSettings const& vsettings);
static Minecraft_selectLevel_t Minecraft_selectLevel = (Minecraft_selectLevel_t) 0x16f38;
// CommandServer
typedef std::string (*CommandServer_parse_t)(unsigned char *command_server, struct ConnectedClient &client, std::string const& command);
static CommandServer_parse_t CommandServer_parse = (CommandServer_parse_t) 0x6aa8c;
// Level
typedef void (*Level_addParticle_t)(unsigned char *level, std::string const& particle, float x, float y, float z, float deltaX, float deltaY, float deltaZ, int count);
static Level_addParticle_t Level_addParticle = (Level_addParticle_t) 0xa449c;
// Gui
typedef void (*Gui_addMessage_t)(unsigned char *gui, std::string const& text);
static Gui_addMessage_t Gui_addMessage = (Gui_addMessage_t) 0x27820;
// ServerSideNetworkHandler
typedef void (*ServerSideNetworkHandler_displayGameMessage_t)(unsigned char *server_side_network_handler, std::string const& message);
static ServerSideNetworkHandler_displayGameMessage_t ServerSideNetworkHandler_displayGameMessage = (ServerSideNetworkHandler_displayGameMessage_t) 0x750c4;
// SimpleChooseLevelScreen
#define SIMPLE_LEVEL_CHOOSE_SCREEN_SIZE 0x68
typedef unsigned char *(*SimpleChooseLevelScreen_t)(unsigned char *simple_choose_level_screen, std::string const& world_name);
static SimpleChooseLevelScreen_t SimpleChooseLevelScreen = (SimpleChooseLevelScreen_t) 0x31404;
// SelectWorldScreen
typedef std::string (*SelectWorldScreen_getUniqueLevelName_t)(unsigned char *screen, std::string const& name);
static SelectWorldScreen_getUniqueLevelName_t SelectWorldScreen_getUniqueLevelName = (SelectWorldScreen_getUniqueLevelName_t) 0x388ec;
// Touch::SelectWorldScreen
static SelectWorldScreen_getUniqueLevelName_t Touch_SelectWorldScreen_getUniqueLevelName = (SelectWorldScreen_getUniqueLevelName_t) 0x3d82c;
// Common
typedef std::string (*Common_getGameVersionString_t)(std::string const& version_suffix);
static Common_getGameVersionString_t Common_getGameVersionString = (Common_getGameVersionString_t) 0x15068;
#endif
#pragma GCC diagnostic pop

View File

@ -0,0 +1,32 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// Patching Functions
#ifdef REBORN_HAS_PATCH_CODE
void _overwrite_call(const char *file, int line, void *start, void *target);
#define overwrite_call(start, target) _overwrite_call(__FILE__, __LINE__, start, target);
void _overwrite_calls(const char *file, int line, void *start, void *target);
#define overwrite_calls(start, target) _overwrite_calls(__FILE__, __LINE__, start, target);
void *extract_from_bl_instruction(unsigned char *from);
void _overwrite(const char *file, int line, void *start, void *target);
#define overwrite(start, target) _overwrite(__FILE__, __LINE__, start, target);
void _patch(const char *file, int line, void *start, unsigned char patch[4]);
#define patch(start, patch) _patch(__FILE__, __LINE__, start, patch);
void _patch_address(const char *file, int line, void *start, void *target);
#define patch_address(start, target) _patch_address(__FILE__, __LINE__, start, target);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -3,6 +3,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iconv.h>
#include <stdint.h>
#include "util.h"
@ -19,34 +21,28 @@
#define string_append(str, format, ...) \
{ \
char *old = *str; \
safe_asprintf(str, "%s" format, *str == NULL ? "" : *str, __VA_ARGS__); \
safe_asprintf(str, "%s" format, *str == NULL ? "" : *str, ##__VA_ARGS__); \
ALLOC_CHECK(*str); \
if (old != NULL && old != *str) { \
free(old); \
} \
}
#ifdef __cplusplus
extern "C" {
#endif
// Sanitize String
#define MINIMUM_SAFE_CHARACTER 32
#define MAXIMUM_SAFE_CHARACTER 126
#define MINIMUM_EXTENDED_SAFE_CHARACTER 128
static inline void sanitize_string(char **str, int max_length, unsigned int allow_newlines) {
// Store Message Length
int length = strlen(*str);
// Truncate Message
if (max_length != -1 && length > max_length) {
(*str)[max_length] = '\0';
length = max_length;
}
// Loop Through Message
for (int i = 0; i < length; i++) {
if (allow_newlines && ((*str)[i] == '\n' || (*str)[i] == '\r')) {
continue;
}
unsigned char c = (unsigned char) (*str)[i];
if ((c < MINIMUM_SAFE_CHARACTER || c > MAXIMUM_SAFE_CHARACTER) && c < MINIMUM_EXTENDED_SAFE_CHARACTER) {
// Replace Illegal Character
(*str)[i] = '?';
}
}
void sanitize_string(char **str, int max_length, unsigned int allow_newlines);
// CP437
void safe_iconv(iconv_t cd, char *input, size_t input_size, char *output, size_t output_size);
char *to_cp437(const char *input);
char *from_cp437(const char *input);
// Starts With
int starts_with(const char *str, const char *prefix);
#ifdef __cplusplus
}
#endif

View File

@ -11,7 +11,7 @@
#define ALLOC_CHECK(obj) \
{ \
if (obj == NULL) { \
ERR("(%s:%i) Memory Allocation Failed", __FILE__, __LINE__); \
ERR("Memory Allocation Failed"); \
} \
}
@ -25,27 +25,22 @@
dlerror(); \
real_##name = (name##_t) dlsym(RTLD_NEXT, #name); \
if (!real_##name) { \
ERR("Error Resolving Symbol: "#name": %s", dlerror()); \
ERR("Error Resolving Symbol: " #name ": %s", dlerror()); \
} \
} \
} \
\
__attribute__((__used__)) return_type name args
// Macro To Reset Environmental Variables To Pre-MCPI State
#define RESET_ENVIRONMENTAL_VARIABLE(name) \
{ \
char *original_env_value = getenv("ORIGINAL_" name); \
if (original_env_value != NULL) { \
setenv(name, original_env_value, 1); \
} else { \
unsetenv(name); \
} \
}
#ifdef __cplusplus
extern "C" {
#endif
// Safe Version Of pipe()
static inline void safe_pipe2(int pipefd[2], int flags) {
if (pipe2(pipefd, flags) != 0) {
ERR("Unable To Create Pipe: %s", strerror(errno));
}
void safe_pipe2(int pipefd[2], int flags);
// Check If Two Percentages Are Different Enough To Be Logged
int is_progress_difference_significant(int32_t new_val, int32_t old_val);
#ifdef __cplusplus
}
#endif

View File

@ -11,7 +11,7 @@
#ifndef __arm__
#error "Patching Code Is ARM Only"
#endif // #ifndef __arm__
#endif
// BL Instruction Magic Number
#define BL_INSTRUCTION 0xeb
@ -44,8 +44,9 @@ struct overwrite_data {
void *replacement;
int found;
};
static void overwrite_calls_callback(void *section, Elf32_Word size, void *data) {
static void overwrite_calls_callback(ElfW(Addr) section_addr, ElfW(Word) size, void *data) {
struct overwrite_data *args = (struct overwrite_data *) data;
void *section = (void *) section_addr;
for (uint32_t i = 0; i < size; i = i + 4) {
unsigned char *addr = ((unsigned char *) section) + i;
@ -71,6 +72,12 @@ static unsigned char *code_block = NULL;
#define CODE_SIZE 8
static int code_block_remaining = CODE_BLOCK_SIZE;
static void _long_overwrite(void *start, void *target) {
unsigned char patch_data[4] = {0x04, 0xf0, 0x1f, 0xe5}; // "ldr pc, [pc, #-0x4]"
_patch(NULL, -1, start, patch_data);
_patch_address(NULL, -1, (void *) (((unsigned char *) start) + 4), target);
}
static void update_code_block(void *target) {
// BL Instructions Can Only Access A Limited Portion of Memory, So This Allocates Memory Closer To The Original Instruction, That When Run, Will Jump Into The Actual Target
if (code_block == NULL) {
@ -78,33 +85,36 @@ static void update_code_block(void *target) {
if (code_block == MAP_FAILED) {
ERR("Unable To Allocate Code Block: %s", strerror(errno));
}
#ifdef DEBUG
INFO("Code Block Allocated At: 0x%08x", (uint32_t) code_block);
#endif
DEBUG("Code Block Allocated At: 0x%08x", (uint32_t) code_block);
}
if (code_block_remaining < CODE_SIZE) {
ERR("%s", "Maximum Amount Of overwrite_calls() Uses Reached");
ERR("Maximum Amount Of overwrite_calls() Uses Reached");
}
_overwrite(NULL, -1, code_block, target);
_long_overwrite(code_block, target);
}
static void increment_code_block() {
code_block = code_block + CODE_SIZE;
code_block_remaining = code_block_remaining - CODE_SIZE;
}
// Overwrite Specific BL Instruction
void _overwrite_call(const char *file, int line, void *start, void *target) {
// Overwrite Specific B(L) Instruction
static void _overwrite_call_internal(const char *file, int line, void *start, void *target, int use_b_instruction) {
// Add New Target To Code Block
update_code_block(target);
uint32_t new_instruction = generate_bl_instruction(start, code_block, 0);
// Patch
uint32_t new_instruction = generate_bl_instruction(start, code_block, use_b_instruction);
_patch(file, line, start, (unsigned char *) &new_instruction);
// Increment Code Block Position
increment_code_block();
}
void _overwrite_call(const char *file, int line, void *start, void *target) {
int use_b_instruction = ((unsigned char *) start)[3] == B_INSTRUCTION;
_overwrite_call_internal(file, line, start, target, use_b_instruction);
}
// Overwrite Function Calls
// Overwrite All B(L) Intrusctions That Target The Specified Address
void _overwrite_calls(const char *file, int line, void *start, void *target) {
// Add New Target To Code Block
update_code_block(target);
@ -116,35 +126,44 @@ void _overwrite_calls(const char *file, int line, void *start, void *target) {
data.replacement = code_block;
data.found = 0;
iterate_text_sections(overwrite_calls_callback, &data);
iterate_segments(overwrite_calls_callback, &data);
// Increment Code Block Position
increment_code_block();
// Check
if (data.found < 1) {
ERR("(%s:%i) Unable To Find Callsites For 0x%08x", file, line, (uint32_t) start);
}
}
// Extract Target Address From B(L) Instruction
void *extract_from_bl_instruction(unsigned char *from) {
unsigned char *pc = ((unsigned char *) from) + 8;
int32_t target = 0;
unsigned char *target_array = (unsigned char *) &target;
target_array[0] = from[0];
target_array[1] = from[1];
target_array[2] = from[2];
int32_t offset = target << 2;
return (void *) (pc + offset);
}
// Overwrite Function
void _overwrite(const char *file, int line, void *start, void *target) {
unsigned char patch_data[4] = {0x04, 0xf0, 0x1f, 0xe5}; // "ldr pc, [pc, #-0x4]"
_patch(file, line, start, patch_data);
_patch_address(file, line, (void *) (((unsigned char *) start) + 4), target);
_overwrite_call_internal(file, line, start, target, 1);
}
// Print Patch Debug Data
#ifdef DEBUG
#define PATCH_PRINTF(file, line, start, str) if (file != NULL) fprintf(stderr, "[PATCH]: (%s:%i) Patching (0x%08x) - "str": 0x%02x 0x%02x 0x%02x 0x%02x\n", file, line, (uint32_t) start, data[0], data[1], data[2], data[3]);
#else
#define PATCH_PRINTF(file, line, start, str) { (void) file; (void) line; (void) start; (void) str; } // Mark As Used
#endif
#define PATCH_PRINTF(file, line, start, str) if (file != NULL) DEBUG("(%s:%i): Patching (0x%08x) - " str ": 0x%02x 0x%02x 0x%02x 0x%02x", file, line, (uint32_t) start, data[0], data[1], data[2], data[3]);
// Patch Instruction
void _patch(const char *file, int line, void *start, unsigned char patch[]) {
void _patch(const char *file, int line, void *start, unsigned char patch[4]) {
if (((uint32_t) start) % 4 != 0) {
ERR("%s", "Invalid Address");
ERR("Invalid Address");
}
size_t page_size = sysconf(_SC_PAGESIZE);
@ -171,6 +190,6 @@ void _patch(const char *file, int line, void *start, unsigned char patch[]) {
// Patch Address
void _patch_address(const char *file, int line, void *start, void *target) {
uint32_t addr = (uint32_t) target;
unsigned char patch_data[4] = {addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, (addr >> 24) & 0xff};
unsigned char *patch_data = (unsigned char *) &addr;
_patch(file, line, start, patch_data);
}

28
libreborn/src/util/elf.c Normal file
View File

@ -0,0 +1,28 @@
#include <libreborn/elf.h>
// Find And Iterate Over All Segments In Current Binary
typedef struct {
segment_callback_t callback;
void *data;
} dl_iterate_callback_data;
static int dl_iterate_callback(struct dl_phdr_info *info, __attribute__((unused)) size_t size, void *data) {
dl_iterate_callback_data *callback_data = (dl_iterate_callback_data *) data;
// Only Search Current Program
if (strcmp(info->dlpi_name, "") == 0) {
for (int i = 0; i < info->dlpi_phnum; i++) {
// Only Executable Segemnts
if (info->dlpi_phdr[i].p_type == PT_LOAD && (info->dlpi_phdr[i].p_flags & PF_X) != 0) {
// Callback
(*callback_data->callback)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, info->dlpi_phdr[i].p_memsz, callback_data->data);
}
}
}
return 0;
}
void iterate_segments(segment_callback_t callback, void *data) {
dl_iterate_callback_data callback_data = {
.callback = callback,
.data = data
};
dl_iterate_phdr(dl_iterate_callback, (void *) &callback_data);
}

169
libreborn/src/util/exec.c Normal file
View File

@ -0,0 +1,169 @@
#include <pthread.h>
#include <libreborn/exec.h>
// Set Environmental Variable
static void setenv_safe(const char *name, const char *value) {
if (value != NULL) {
setenv(name, value, 1);
} else {
unsetenv(name);
}
}
void set_and_print_env(const char *name, const char *value) {
// Print New Value
DEBUG("Set %s = %s", name, value != NULL ? value : "(unset)");
// Set The Value
setenv_safe(name, value);
}
// Safe execvpe()
#define handle_environmental_variable(var) \
{ \
const char *full_var = is_arm_component ? "MCPI_ARM_" var : "MCPI_NATIVE_" var; \
const char *var_value = getenv(full_var); \
set_and_print_env(var, var_value); \
}
void setup_exec_environment(int is_arm_component) {
for_each_special_environmental_variable(handle_environmental_variable);
}
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]) {
// Log
DEBUG("Running Command:");
for (int i = 0; argv[i] != NULL; i++) {
DEBUG(" %s", argv[i]);
}
// Run
int ret = execvpe(argv[0], (char *const *) argv, (char *const *) envp);
if (ret == -1) {
if (errno == ENOENT && strcmp(argv[0], "qemu-qrm")) {
ERR("Unable to find QEMU! To install on Ubuntu/Debian, run \"sudo apt install qemu-user\". To install on Arch Linux, run \"sudo pacman -Sy qemu-user\".");
}
ERR("Unable To Execute Program: %s: %s", argv[0], strerror(errno));
} else {
IMPOSSIBLE();
}
}
// Chop Off Last Component
void chop_last_component(char **str) {
size_t length = strlen(*str);
for (size_t i = 0; i < length; i++) {
size_t j = length - i - 1;
if ((*str)[j] == '/') {
(*str)[j] = '\0';
break;
}
}
}
// Get Binary Directory (Remember To Free)
char *get_binary_directory() {
// Get Path To Current Executable
char *exe = realpath("/proc/self/exe", NULL);
ALLOC_CHECK(exe);
// Chop Off Last Component
chop_last_component(&exe);
// Return
return exe;
}
// Run Command And Get Output
char *run_command(const char *const command[], int *exit_status) {
// Store Output
int output_pipe[2];
safe_pipe2(output_pipe, 0);
// Run
pid_t ret = fork();
if (ret == -1) {
ERR("Unable To Run Command: %s", strerror(errno));
} else if (ret == 0) {
// Child Process
// Pipe stdout
dup2(output_pipe[1], STDOUT_FILENO);
close(output_pipe[0]);
close(output_pipe[1]);
// Setup Environment
setup_exec_environment(0);
// Run
safe_execvpe(command, (const char *const *) environ);
} else {
// Parent Process
track_child(ret);
// Read stdout
close(output_pipe[1]);
char *output = NULL;
#define BUFFER_SIZE 1024
char buf[BUFFER_SIZE];
ssize_t bytes_read = 0;
while ((bytes_read = read(output_pipe[0], (void *) buf, BUFFER_SIZE - 1 /* Account For NULL-Terminator */)) > 0) {
buf[bytes_read] = '\0';
string_append(&output, "%s", buf);
}
close(output_pipe[0]);
// Get Return Code
int status;
waitpid(ret, &status, 0);
untrack_child(ret);
if (exit_status != NULL) {
*exit_status = status;
}
// Return
return output;
}
}
// Get Exit Status String
void get_exit_status_string(int status, char **out) {
if (out != NULL) {
*out =NULL;
if (WIFEXITED(status)) {
safe_asprintf(out, ": Exit Code: %i", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
safe_asprintf(out, ": Signal: %i%s", WTERMSIG(status), WCOREDUMP(status) ? " (Core Dumped)" : "");
} else {
safe_asprintf(out, ": Terminated");
}
}
}
// Track Children
#define MAX_CHILDREN 128
static pid_t children[MAX_CHILDREN] = { 0 };
static pthread_mutex_t children_lock = PTHREAD_MUTEX_INITIALIZER;
void track_child(pid_t pid) {
pthread_mutex_lock(&children_lock);
for (int i = 0; i < MAX_CHILDREN; i++) {
if (children[i] == 0) {
children[i] = pid;
break;
}
}
pthread_mutex_unlock(&children_lock);
}
void untrack_child(pid_t pid) {
pthread_mutex_lock(&children_lock);
for (int i = 0; i < MAX_CHILDREN; i++) {
if (children[i] == pid) {
children[i] = 0;
}
}
pthread_mutex_unlock(&children_lock);
}
void murder_children() {
pthread_mutex_lock(&children_lock);
for (int i = 0; i < MAX_CHILDREN; i++) {
if (children[i] != 0) {
kill(children[i], SIGTERM);
}
}
pthread_mutex_unlock(&children_lock);
}

148
libreborn/src/util/string.c Normal file
View File

@ -0,0 +1,148 @@
#include <iconv.h>
#include <stdint.h>
#include <libreborn/string.h>
// Sanitize String
void sanitize_string(char **str, int max_length, unsigned int allow_newlines) {
// Store Message Length
int length = strlen(*str);
// Truncate Message
if (max_length != -1 && length > max_length) {
(*str)[max_length] = '\0';
length = max_length;
}
// Loop Through Message
if (!allow_newlines) {
for (int i = 0; i < length; i++) {
if ((*str)[i] == '\n' || (*str)[i] == '\r') {
// Replace Newline
(*str)[i] = ' ';
}
}
}
}
// Minecraft-Flavored CP437
void safe_iconv(iconv_t cd, char *input, size_t input_size, char *output, size_t output_size) {
iconv(cd, &input, &input_size, &output, &output_size);
}
#define CP437_CHARACTERS 256
static const char *cp437_characters_map[CP437_CHARACTERS] = {
"\0", "", "", "", "", "", "", "", "", "", "\n", "", "", "\r", "", "",
"", "", "", "", "", "§", "", "", "", "", "", "", "", "", "", "",
" ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?",
"@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
"P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_",
"`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "",
"Ç", "ü", "é", "â", "ä", "à", "å", "ç", "ê", "ë", "è", "ï", "î", "ì", "Ä", "Å",
"É", "æ", "Æ", "ô", "ö", "ò", "û", "ù", "ÿ", "Ö", "Ü", "¢", "£", "¥", "", "ƒ",
"á", "í", "ó", "ú", "ñ", "Ñ", "ª", "º", "¿", "", "¬", "½", "¼", "¡", "«", "»",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"α", "ß", "Γ", "π", "Σ", "σ", "µ", "τ", "Φ", "Θ", "Ω", "δ", "", "φ", "ε", "",
"", "±", "", "", "", "", "÷", "", "°", "", "·", "", "", "²", "", "©"
};
static uint32_t *get_cp437_characters_codepoint_map() {
static uint32_t map[CP437_CHARACTERS];
static int is_setup = 0;
if (!is_setup) {
// Build Map
iconv_t cd = iconv_open("UTF-32LE", "UTF-8");
if (cd != (iconv_t) -1) {
size_t str_size = 4;
uint32_t *str = (uint32_t *) malloc(str_size);
ALLOC_CHECK(str);
for (int i = 0; i < CP437_CHARACTERS; i++) {
// Convert to UTF-32, Then Extract Codepoint
safe_iconv(cd, (char *) cp437_characters_map[i], strlen(cp437_characters_map[i]), (char *) str, str_size);
// Extract
map[i] = str[0];
}
// Free
free(str);
iconv_close(cd);
} else {
IMPOSSIBLE();
}
is_setup = 1;
}
return map;
}
char *to_cp437(const char *input) {
// Convert To UTF-32 For Easier Parsing
size_t in_size = strlen(input);
size_t utf32_str_size = in_size * 4;
size_t real_utf32_str_size = utf32_str_size + 4 /* NULL-terminator */;
uint32_t *utf32_str = (uint32_t *) malloc(real_utf32_str_size);
ALLOC_CHECK(utf32_str);
memset(utf32_str, 0, real_utf32_str_size);
iconv_t cd = iconv_open("UTF-32LE", "UTF-8");
if (cd != (iconv_t) -1) {
safe_iconv(cd, (char *) input, in_size, (char *) utf32_str, utf32_str_size);
iconv_close(cd);
} else {
IMPOSSIBLE();
}
// Allocate String
size_t cp437_str_size;
for (cp437_str_size = 0; utf32_str[cp437_str_size] != 0; cp437_str_size++);
size_t real_cp437_str_size = cp437_str_size + 1 /* NULL-terminator */;
char *cp437_str = (char *) malloc(real_cp437_str_size);
ALLOC_CHECK(cp437_str);
memset(cp437_str, 0, real_cp437_str_size);
// Handle Characters
for (size_t i = 0; utf32_str[i] != 0; i++) {
uint32_t codepoint = utf32_str[i];
for (int j = 0; j < CP437_CHARACTERS; j++) {
uint32_t test_codepoint = get_cp437_characters_codepoint_map()[j];
if (codepoint == test_codepoint) {
cp437_str[i] = j;
break;
}
}
if (cp437_str[i] == '\0') {
cp437_str[i] = '?';
}
}
// Free
free(utf32_str);
// Return
return cp437_str;
}
char *from_cp437(const char *input) {
// Convert To UTF-32 For Easier Parsing
size_t in_size = strlen(input);
size_t utf32_str_size = in_size * 4;
size_t real_utf32_str_size = utf32_str_size + 4 /* NULL-terminator */;
uint32_t *utf32_str = (uint32_t *) malloc(real_utf32_str_size);
ALLOC_CHECK(utf32_str);
memset(utf32_str, 0, real_utf32_str_size);
// Handle Characters
for (size_t i = 0; input[i] != '\0'; i++) {
utf32_str[i] = get_cp437_characters_codepoint_map()[(uint32_t) input[i]];
}
// Convert To UTF-8
size_t out_size = utf32_str_size;
size_t real_out_size = utf32_str_size + 1 /* NULL-terminator */;
char *output = (char *) malloc(real_out_size);
ALLOC_CHECK(output);
memset(output, 0, real_out_size);
iconv_t cd = iconv_open("UTF-8", "UTF-32LE");
if (cd != (iconv_t) -1) {
safe_iconv(cd, (char *) utf32_str, utf32_str_size, output, out_size);
iconv_close(cd);
} else {
IMPOSSIBLE();
}
// Return
return output;
}
// Starts With
int starts_with(const char *str, const char *prefix) {
return strncmp(prefix, str, strlen(prefix)) == 0;
}

24
libreborn/src/util/util.c Normal file
View File

@ -0,0 +1,24 @@
#include <libreborn/util.h>
// Safe Version Of pipe()
void safe_pipe2(int pipefd[2], int flags) {
if (pipe2(pipefd, flags) != 0) {
ERR("Unable To Create Pipe: %s", strerror(errno));
}
}
// Check If Two Percentages Are Different Enough To Be Logged
#define SIGNIFICANT_PROGRESS 5
int is_progress_difference_significant(int32_t new_val, int32_t old_val) {
if (new_val != old_val) {
if (new_val == -1 || old_val == -1) {
return 1;
} else if (new_val == 0 || new_val == 100) {
return 1;
} else {
return new_val - old_val >= SIGNIFICANT_PROGRESS;
}
} else {
return 0;
}
}

View File

@ -1,29 +1,28 @@
project(media-layer)
# Check Options
if(MCPI_USE_MEDIA_LAYER_PROXY)
if(MCPI_SERVER_MODE)
message(FATAL_ERROR "Server Mode With Media Layer Proxy Configuration Is Redundant")
endif()
if(MCPI_BUILD_MODE STREQUAL "both")
message(FATAL_ERROR "Media Layer Proxy Is Redundant When Building ARM And Native Components In The Same Build")
endif()
endif()
# Add Headers
add_library(media-layer-headers INTERFACE)
target_include_directories(media-layer-headers INTERFACE include)
target_include_directories(
media-layer-headers
INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${MCPI_SDK_INCLUDE_DIR}/media-layer>"
)
# SDK
if(BUILD_ARM_COMPONENTS)
install(TARGETS media-layer-headers EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
install(DIRECTORY "include/" DESTINATION "${MCPI_SDK_INCLUDE_DIR}/media-layer")
endif()
# Add Extras
add_subdirectory(extras)
# Add Core
add_subdirectory(core)
if((BUILD_NATIVE_COMPONENTS AND MCPI_USE_MEDIA_LAYER_PROXY) OR (BUILD_ARM_COMPONENTS AND NOT MCPI_USE_MEDIA_LAYER_PROXY))
add_subdirectory(core)
endif()
# Add Proxy
if(MCPI_USE_MEDIA_LAYER_PROXY)
add_subdirectory(proxy)
endif()
# Add Stubs
add_subdirectory(stubs)
# Add Extras
add_subdirectory(extras)

View File

@ -1,34 +1,32 @@
project(media-layer-core)
# Dependencies
add_subdirectory(dependencies)
# OpenGL
add_subdirectory(gles)
# Configuration
set(CORE_SRC src/base.cpp src/media.c src/screenshot.c) # SDL Re-Implementation Using GLFW
set(CORE_SRC src/base.cpp src/media.c $<TARGET_OBJECTS:media-layer-extras>) # SDL Re-Implementation Using GLFW
if(NOT MCPI_HEADLESS_MODE)
list(APPEND CORE_SRC src/audio/api.cpp src/audio/engine.c src/audio/file.cpp)
else()
list(APPEND CORE_SRC src/audio/stubs.c)
endif()
# Build
if(MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_NATIVE_COMPONENTS)
# Building Native Components
add_library(media-layer-core OBJECT ${CORE_SRC}) # Dependencies Are Setup Later
elseif(NOT MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_ARM_COMPONENTS)
# Building ARM Components
add_library(media-layer-core SHARED ${CORE_SRC}) # Dependencies Are Setup Later
# Install
install(TARGETS media-layer-core DESTINATION "${MCPI_LIB_DIR}")
endif()
# Configure Media Layer Core If Built
if(TARGET media-layer-core)
# Link
target_link_libraries(media-layer-core media-layer-headers reborn-headers pthread dl)
if(NOT MCPI_SERVER_MODE)
# Find GLFW
find_package(glfw3 3.2 REQUIRED)
# Find FreeImage
find_library(FREEIMAGE_LIBRARY NAMES freeimage libfreeimage.so.3 REQUIRED)
# Not Needed In Server Mode
target_link_libraries(media-layer-core "${FREEIMAGE_LIBRARY}" GLESv1_CM glfw)
endif()
endif()
# Add Symlinks So MCPI Can Locate Libraries
add_library(media-layer-core SHARED ${CORE_SRC}) # Dependencies Are Setup Later
# Install
install(TARGETS media-layer-core DESTINATION "${MCPI_LIB_DIR}")
if(BUILD_ARM_COMPONENTS)
install_symlink("libmedia-layer-core.so" "${MCPI_LIB_DIR}/libSDL-1.2.so.0")
install(TARGETS media-layer-core EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
endif()
# Link
target_link_libraries(media-layer-core PUBLIC media-layer-headers PUBLIC reborn-util PUBLIC GLESv1_CM PUBLIC dl)
if(NOT MCPI_HEADLESS_MODE)
# OpenAL
find_library(OPENAL_LIBRARY NAMES openal REQUIRED)
# Link
target_link_libraries(media-layer-core PRIVATE "${OPENAL_LIBRARY}" PRIVATE m PRIVATE glfw)
endif()

View File

@ -0,0 +1,6 @@
project(media-layer-core-dependencies)
# GLFW
if(NOT MCPI_HEADLESS_MODE)
add_subdirectory(glfw)
endif()

View File

@ -0,0 +1,31 @@
project(glfw)
# Silence Warnings
add_compile_options(-w)
## GLFW
# Download
set(BUILD_SHARED_LIBS TRUE CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES FALSE CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS FALSE CACHE BOOL "" FORCE)
set(GLFW_BUILD_DOCS FALSE CACHE BOOL "" FORCE)
set(GLFW_INSTALL FALSE CACHE BOOL "" FORCE)
set(GLFW_BUILD_WIN32 FALSE CACHE BOOL "" FORCE)
set(GLFW_BUILD_COCOA FALSE CACHE BOOL "" FORCE)
set(GLFW_BUILD_X11 TRUE CACHE BOOL "" FORCE)
set(GLFW_BUILD_WAYLAND TRUE CACHE BOOL "" FORCE)
set(GLFW_LIBRARY_TYPE "SHARED" CACHE BOOL "" FORCE)
add_subdirectory(src EXCLUDE_FROM_ALL)
# Ensure Build
add_custom_target(glfw-build ALL DEPENDS glfw)
# Install
install(TARGETS glfw DESTINATION "${MCPI_LIB_DIR}")
if(BUILD_ARM_COMPONENTS)
install(TARGETS glfw EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
endif()
# License
install(FILES src/LICENSE.md DESTINATION "${MCPI_LEGAL_DIR}/glfw")

@ -0,0 +1 @@
Subproject commit c18851f52ec9704eb06464058a600845ec1eada1

View File

@ -0,0 +1,32 @@
project(media-layer-gles)
# Build
if(MCPI_HEADLESS_MODE)
# Stubs For Headless Mode
set(GLES_SRC src/stubs.c)
elseif(MCPI_USE_GLES1_COMPATIBILITY_LAYER)
# GLESv1_CM Compatibility Layer
set(GLES_SRC src/compatibility-layer/state.c src/compatibility-layer/passthrough.c src/compatibility-layer/matrix.c src/compatibility-layer/draw.c src/compatibility-layer/buffer.cpp)
else()
# Passthrough To glfwGetProcAddress()
set(GLES_SRC src/passthrough.c)
endif()
add_library(GLESv1_CM SHARED ${GLES_SRC})
if(NOT MCPI_HEADLESS_MODE)
target_link_libraries(GLESv1_CM PRIVATE glfw PUBLIC reborn-util PRIVATE dl PRIVATE m)
# Shaders
if(MCPI_USE_GLES1_COMPATIBILITY_LAYER)
embed_resource(GLESv1_CM src/compatibility-layer/shaders/main.vsh)
embed_resource(GLESv1_CM src/compatibility-layer/shaders/main.fsh)
endif()
endif()
# Common
target_link_libraries(GLESv1_CM PUBLIC media-layer-headers)
set_target_properties(GLESv1_CM PROPERTIES SOVERSION "1")
# Install
install(TARGETS GLESv1_CM DESTINATION "${MCPI_LIB_DIR}")
# SDK
if(BUILD_ARM_COMPONENTS)
install(TARGETS GLESv1_CM EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
endif()

View File

@ -0,0 +1,35 @@
#include <unordered_map>
#include <GLES/gl.h>
#include "../passthrough.h"
// Store Buffers
static std::unordered_map<GLuint, GLuint> buffers_map;
// Get Buffer
GL_FUNC(glGenBuffers, void, (GLsizei n, GLuint *buffers));
static GLuint get_real_buffer(GLuint fake_buffer) {
if (buffers_map.count(fake_buffer) > 0) {
return buffers_map[fake_buffer];
} else {
GLuint new_buffer;
real_glGenBuffers()(1, &new_buffer);
buffers_map[fake_buffer] = new_buffer;
return get_real_buffer(fake_buffer);
}
}
// Convert Fake Buffers To Real Buffers When Calling GL
GL_FUNC(glBindBuffer, void, (GLenum target, GLuint buffer));
void glBindBuffer(GLenum target, GLuint buffer) {
real_glBindBuffer()(target, get_real_buffer(buffer));
}
GL_FUNC(glDeleteBuffers, void, (GLsizei n, const GLuint *buffers));
void glDeleteBuffers(GLsizei n, const GLuint *buffers) {
for (int i = 0; i < n; i++) {
if (buffers_map.count(buffers[i]) > 0) {
real_glDeleteBuffers()(1, &buffers_map[i]);
buffers_map.erase(buffers[i]);
}
}
}

View File

@ -0,0 +1,204 @@
#include "state.h"
#include "../passthrough.h"
#include <GLES/gl.h>
#include <libreborn/libreborn.h>
// Shaders
#define REAL_GL_FRAGMENT_SHADER 0x8b30
#define REAL_GL_VERTEX_SHADER 0x8b31
#define REAL_GL_INFO_LOG_LENGTH 0x8b84
#define REAL_GL_COMPILE_STATUS 0x8b81
GL_FUNC(glUseProgram, void, (GLuint program));
GL_FUNC(glGetUniformLocation, GLint, (GLuint program, const GLchar *name));
GL_FUNC(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value));
GL_FUNC(glUniform1i, void, (GLint location, GLint v0));
GL_FUNC(glUniform1f, void, (GLint location, GLfloat v0));
GL_FUNC(glUniform4f, void, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3));
GL_FUNC(glGetAttribLocation, GLint, (GLuint program, const GLchar *name));
GL_FUNC(glEnableVertexAttribArray, void, (GLuint index));
GL_FUNC(glDisableVertexAttribArray, void, (GLuint index));
GL_FUNC(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer));
GL_FUNC(glVertexAttrib3f, void, (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2));
GL_FUNC(glVertexAttrib4f, void, (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3));
GL_FUNC(glCreateShader, GLuint, (GLenum type));
GL_FUNC(glShaderSource, void, (GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length));
GL_FUNC(glCompileShader, void, (GLuint shader));
GL_FUNC(glCreateProgram, GLuint, ());
GL_FUNC(glAttachShader, void, (GLuint program, GLuint shader));
GL_FUNC(glLinkProgram, void, (GLuint program));
GL_FUNC(glGetShaderiv, void, (GLuint shader, GLenum pname, GLint *params));
GL_FUNC(glGetShaderInfoLog, void, (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog));
// Compile Shader
static void log_shader(GLuint shader, const char *name) {
// Log
GLint log_length = 0;
real_glGetShaderiv()(shader, REAL_GL_INFO_LOG_LENGTH, &log_length);
GLchar *log = malloc(log_length * sizeof (GLchar));
ALLOC_CHECK(log);
real_glGetShaderInfoLog()(shader, log_length, &log_length, log);
if (log_length > 0) {
if (log_length > 1 && log[log_length - 1] == '\n') {
log[log_length - 1] = '\0';
}
DEBUG("%s Shader Compile Log: %s", name, log);
}
free(log);
// Check Status
GLint is_compiled = 0;
real_glGetShaderiv()(shader, REAL_GL_COMPILE_STATUS, &is_compiled);
if (!is_compiled) {
ERR("Failed To Compile %s Shader", name);
}
}
static GLuint compile_shader(const char *vertex_shader_text, const int vertex_shader_length, const char *fragment_shader_text, const int fragment_shader_length) {
// Vertex Shader
const GLuint vertex_shader = real_glCreateShader()(REAL_GL_VERTEX_SHADER);
real_glShaderSource()(vertex_shader, 1, &vertex_shader_text, &vertex_shader_length);
real_glCompileShader()(vertex_shader);
log_shader(vertex_shader, "Vertex");
// Fragment Shader
const GLuint fragment_shader = real_glCreateShader()(REAL_GL_FRAGMENT_SHADER);
real_glShaderSource()(fragment_shader, 1, &fragment_shader_text, &fragment_shader_length);
real_glCompileShader()(fragment_shader);
log_shader(fragment_shader, "Fragment");
// Link
GLuint program = real_glCreateProgram()();
real_glAttachShader()(program, vertex_shader);
real_glAttachShader()(program, fragment_shader);
real_glLinkProgram()(program);
// Return
return program;
}
// Shader
extern unsigned char main_vsh[];
extern size_t main_vsh_len;
extern unsigned char main_fsh[];
extern size_t main_fsh_len;
static GLuint get_shader() {
static GLuint program = 0;
if (program == 0) {
program = compile_shader((const char *) main_vsh, main_vsh_len, (const char *) main_fsh, main_fsh_len);
}
return program;
}
// Shader Switching
static void use_shader(GLuint program) {
static GLuint current_program = 0;
if (current_program != program) {
real_glUseProgram()(program);
current_program = program;
}
}
// Array Pointer Drawing
GL_FUNC(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count));
#define lazy_uniform(name) \
static GLint name##_handle = -1; \
if (name##_handle == -1) { \
name##_handle = real_glGetUniformLocation()(program, #name); \
}
void glDrawArrays(GLenum mode, GLint first, GLsizei count) {
// Verify
if (gl_state.array_pointers.vertex.size != 3 || !gl_state.array_pointers.vertex.enabled || gl_state.array_pointers.vertex.type != GL_FLOAT) {
ERR("Unsupported Vertex Conifguration");
}
// Check Mode
int use_color_pointer = gl_state.array_pointers.color.enabled;
if (use_color_pointer && (gl_state.array_pointers.color.size != 4 || gl_state.array_pointers.color.type != GL_UNSIGNED_BYTE)) {
ERR("Unsupported Color Conifguration");
}
int use_texture = gl_state.texture_2d && gl_state.array_pointers.tex_coord.enabled;
if (use_texture && (gl_state.array_pointers.tex_coord.size != 2 || gl_state.array_pointers.tex_coord.type != GL_FLOAT)) {
ERR("Unsupported Texture Conifguration");
}
// Load Shader
GLuint program = get_shader();
use_shader(program);
// Projection Matrix
lazy_uniform(u_projection);
matrix_t *p = &gl_state.matrix_stacks.projection.stack[gl_state.matrix_stacks.projection.i];
real_glUniformMatrix4fv()(u_projection_handle, 1, 0, (GLfloat *) &p->data[0][0]);
// Model View Matrix
lazy_uniform(u_model_view);
p = &gl_state.matrix_stacks.model_view.stack[gl_state.matrix_stacks.model_view.i];
real_glUniformMatrix4fv()(u_model_view_handle, 1, 0, (GLfloat *) &p->data[0][0]);
// Has Texture
lazy_uniform(u_has_texture); \
real_glUniform1i()(u_has_texture_handle, use_texture); \
// Texture Matrix
lazy_uniform(u_texture);
p = &gl_state.matrix_stacks.texture.stack[gl_state.matrix_stacks.texture.i];
real_glUniformMatrix4fv()(u_texture_handle, 1, 0, (GLfloat *) &p->data[0][0]);
// Texture Unit
lazy_uniform(u_texture_unit);
real_glUniform1i()(u_texture_unit_handle, 0);
// Alpha Test
lazy_uniform(u_alpha_test);
real_glUniform1i()(u_alpha_test_handle, gl_state.alpha_test);
// Color
GLint a_color_handle = real_glGetAttribLocation()(program, "a_color");
if (use_color_pointer) {
real_glVertexAttribPointer()(a_color_handle, gl_state.array_pointers.color.size, gl_state.array_pointers.color.type, 1, gl_state.array_pointers.color.stride, gl_state.array_pointers.color.pointer);
real_glEnableVertexAttribArray()(a_color_handle);
} else {
real_glVertexAttrib4f()(a_color_handle, gl_state.color.red, gl_state.color.green, gl_state.color.blue, gl_state.color.alpha);
}
// Fog
lazy_uniform(u_fog);
real_glUniform1i()(u_fog_handle, gl_state.fog.enabled);
if (gl_state.fog.enabled) {
lazy_uniform(u_fog_color);
real_glUniform4f()(u_fog_color_handle, gl_state.fog.color[0], gl_state.fog.color[1], gl_state.fog.color[2], gl_state.fog.color[3]);
lazy_uniform(u_fog_is_linear);
real_glUniform1i()(u_fog_is_linear_handle, gl_state.fog.mode == GL_LINEAR);
lazy_uniform(u_fog_start);
real_glUniform1f()(u_fog_start_handle, gl_state.fog.start);
lazy_uniform(u_fog_end);
real_glUniform1f()(u_fog_end_handle, gl_state.fog.end);
}
// Vertices
GLint a_vertex_coords_handle = real_glGetAttribLocation()(program, "a_vertex_coords");
real_glVertexAttribPointer()(a_vertex_coords_handle, gl_state.array_pointers.vertex.size, gl_state.array_pointers.vertex.type, 0, gl_state.array_pointers.vertex.stride, gl_state.array_pointers.vertex.pointer);
real_glEnableVertexAttribArray()(a_vertex_coords_handle);
// Texture Coordinates
GLint a_texture_coords_handle = real_glGetAttribLocation()(program, "a_texture_coords");
if (use_texture) {
real_glVertexAttribPointer()(a_texture_coords_handle, gl_state.array_pointers.tex_coord.size, gl_state.array_pointers.tex_coord.type, 0, gl_state.array_pointers.tex_coord.stride, gl_state.array_pointers.tex_coord.pointer);
real_glEnableVertexAttribArray()(a_texture_coords_handle);
} else {
real_glVertexAttrib3f()(a_texture_coords_handle, 0, 0, 0);
}
// Draw
real_glDrawArrays()(mode, first, count);
// Cleanup
if (use_color_pointer) {
real_glDisableVertexAttribArray()(a_color_handle);
}
real_glDisableVertexAttribArray()(a_vertex_coords_handle);
if (use_texture) {
real_glDisableVertexAttribArray()(a_texture_coords_handle);
}
}

View File

@ -0,0 +1,131 @@
#include <math.h>
#include <string.h>
#include <libreborn/libreborn.h>
#include "state.h"
// Matrix Common
static void matrix_copy(matrix_t *src, matrix_t *dst) {
memcpy((void *) dst->data, (void *) src->data, MATRIX_DATA_SIZE);
}
// Identity Matrix
static matrix_t identity_matrix = {
.data = {
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1}
}
};
static void init_matrix_stack(matrix_stack_t *stack) {
matrix_copy(&identity_matrix, &stack->stack[0]);
}
__attribute__((constructor)) static void init_matrix_stacks() {
init_matrix_stack(&gl_state.matrix_stacks.model_view);
init_matrix_stack(&gl_state.matrix_stacks.projection);
init_matrix_stack(&gl_state.matrix_stacks.texture);
}
// Matrix Mode
static matrix_stack_t *get_matrix_stack() {
switch (gl_state.matrix_stacks.mode) {
case GL_MODELVIEW: {
return &gl_state.matrix_stacks.model_view;
}
case GL_PROJECTION: {
return &gl_state.matrix_stacks.projection;
}
case GL_TEXTURE: {
return &gl_state.matrix_stacks.texture;
}
default: {
ERR("Unsupported Matrix Mode: %i", gl_state.matrix_stacks.mode);
}
}
}
// Matrix Functions
void glMatrixMode(GLenum mode) {
gl_state.matrix_stacks.mode = mode;
}
void glPopMatrix() {
get_matrix_stack()->i--;
}
void glLoadIdentity() {
matrix_stack_t *stack = get_matrix_stack();
matrix_copy(&identity_matrix, &stack->stack[stack->i]);
}
void glPushMatrix() {
matrix_stack_t *stack = get_matrix_stack();
matrix_copy(&stack->stack[stack->i], &stack->stack[stack->i + 1]);
stack->i++;
}
void glMultMatrixf(const GLfloat *m) {
matrix_t new_matrix;
matrix_stack_t *stack = get_matrix_stack();
matrix_t *current_matrix = &stack->stack[stack->i];
for (int x = 0; x < MATRIX_SIZE; x++) {
for (int y = 0; y < MATRIX_SIZE; y++) {
GLfloat result = 0;
for (int i = 0; i < MATRIX_SIZE; i++) {
result += (current_matrix->data[i][y] * m[(x * MATRIX_SIZE) + i]);
}
new_matrix.data[x][y] = result;
}
}
matrix_copy(&new_matrix, current_matrix);
}
void glScalef(GLfloat x, GLfloat y, GLfloat z) {
GLfloat m[] = {
x, 0, 0, 0,
0, y, 0, 0,
0, 0, z, 0,
0, 0, 0, 1
};
glMultMatrixf(m);
}
void glTranslatef(GLfloat x, GLfloat y, GLfloat z) {
GLfloat m[] = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
x, y, z, 1
};
glMultMatrixf(m);
}
void glOrthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far) {
GLfloat m[] = {
(2.f / (right - left)), 0, 0, 0,
0, (2.f / (top - bottom)), 0, 0,
0, 0, (-2.f / (far - near)), 0,
-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((far + near) / (far - near)), 1
};
glMultMatrixf(m);
}
#define DEG2RAD (M_PI / 180.f)
void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
// Normalize
GLfloat length = sqrtf((x * x) + (y * y) + (z * z));
x /= length;
y /= length;
z /= length;
// Values
GLfloat angle_radians = angle * DEG2RAD;
GLfloat c = cosf(angle_radians);
GLfloat s = sinf(angle_radians);
GLfloat x2 = x * x;
GLfloat y2 = y * y;
GLfloat z2 = z * z;
// Multiply
GLfloat m[] = {
x2 * (1.f - c) + c, (x * y) * (1.f - c) + (z * s), (x * z) * (1.f - c) - (y * s), 0,
(x * y) * (1.f - c) - (z * s), y2 * (1.f - c) + c, (y * z) * (1.f - c) + (x * s), 0,
(x * z) * (1.f - c) + (y * s), (y * z) * (1.f - c) - (x * s), z2 * (1.f - c) + c, 0,
0, 0, 0, 1.f
};
glMultMatrixf(m);
}

View File

@ -0,0 +1,9 @@
#include <GLES/gl.h>
// Matrix Common
#define MATRIX_SIZE 4
#define MATRIX_DATA_SIZE (sizeof (float) * MATRIX_SIZE * MATRIX_SIZE)
// OpenGL Matricies Are Column-Major
typedef struct {
GLfloat data[MATRIX_SIZE][MATRIX_SIZE];
} matrix_t;

View File

@ -0,0 +1,105 @@
#include <GLES/gl.h>
#include "../passthrough.h"
// Simple v1.1 -> v2.0 Passthrough Functions
GL_FUNC(glLineWidth, void, (GLfloat width));
void glLineWidth(GLfloat width) {
real_glLineWidth()(width);
}
GL_FUNC(glBlendFunc, void, (GLenum sfactor, GLenum dfactor));
void glBlendFunc(GLenum sfactor, GLenum dfactor) {
real_glBlendFunc()(sfactor, dfactor);
}
GL_FUNC(glClear, void, (GLbitfield mask));
void glClear(GLbitfield mask) {
real_glClear()(mask);
}
GL_FUNC(glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage));
void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {
real_glBufferData()(target, size, data, usage);
}
GL_FUNC(glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height));
void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
real_glScissor()(x, y, width, height);
}
GL_FUNC(glTexParameteri, void, (GLenum target, GLenum pname, GLint param));
void glTexParameteri(GLenum target, GLenum pname, GLint param) {
real_glTexParameteri()(target, pname, param);
}
GL_FUNC(glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels));
void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) {
real_glTexImage2D()(target, level, internalformat, width, height, border, format, type, pixels);
}
GL_FUNC(glPolygonOffset, void, (GLfloat factor, GLfloat units));
void glPolygonOffset(GLfloat factor, GLfloat units) {
real_glPolygonOffset()(factor, units);
}
GL_FUNC(glDepthRangef, void, (GLclampf near, GLclampf far));
void glDepthRangef(GLclampf near, GLclampf far) {
real_glDepthRangef()(near, far);
}
GL_FUNC(glDepthFunc, void, (GLenum func));
void glDepthFunc(GLenum func) {
real_glDepthFunc()(func);
}
GL_FUNC(glClearColor, void, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha));
void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
real_glClearColor()(red, green, blue, alpha);
}
GL_FUNC(glDepthMask, void, (GLboolean flag));
void glDepthMask(GLboolean flag) {
real_glDepthMask()(flag);
}
GL_FUNC(glHint, void, (GLenum target, GLenum mode));
void glHint(GLenum target, GLenum mode) {
if (target != GL_PERSPECTIVE_CORRECTION_HINT) {
real_glHint()(target, mode);
}
}
GL_FUNC(glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha));
void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
real_glColorMask()(red, green, blue, alpha);
}
GL_FUNC(glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels));
void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {
real_glTexSubImage2D()(target, level, xoffset, yoffset, width, height, format, type, pixels);
}
GL_FUNC(glGenTextures, void, (GLsizei n, GLuint *textures));
void glGenTextures(GLsizei n, GLuint *textures) {
real_glGenTextures()(n, textures);
}
GL_FUNC(glDeleteTextures, void, (GLsizei n, const GLuint *textures));
void glDeleteTextures(GLsizei n, const GLuint *textures) {
real_glDeleteTextures()(n, textures);
}
GL_FUNC(glBindTexture, void, (GLenum target, GLuint texture));
void glBindTexture(GLenum target, GLuint texture) {
real_glBindTexture()(target, texture);
}
GL_FUNC(glCullFace, void, (GLenum mode));
void glCullFace(GLenum mode) {
real_glCullFace()(mode);
}
GL_FUNC(glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height));
void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
real_glViewport()(x, y, width, height);
}
GL_FUNC(glIsEnabled, GLboolean, (GLenum cap));
GLboolean glIsEnabled(GLenum cap) {
return real_glIsEnabled()(cap);
}
GL_FUNC(glGetIntegerv, void, (GLenum pname, GLint *data));
void glGetIntegerv(GLenum pname, GLint *data) {
real_glGetIntegerv()(pname, data);
}
GL_FUNC(glReadPixels, void, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data));
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data) {
real_glReadPixels()(x, y, width, height, format, type, data);
}
void glShadeModel(__attribute__((unused)) GLenum mode) {
// Do Nothing
}
void glNormal3f(__attribute__((unused)) GLfloat nx, __attribute__((unused)) GLfloat ny, __attribute__((unused)) GLfloat nz) {
// Do Nothing
}

View File

@ -0,0 +1,39 @@
#version 100
precision mediump float;
// Texture
uniform bool u_has_texture;
uniform sampler2D u_texture_unit;
// Color
varying vec4 v_color;
varying vec4 v_texture_pos;
// Alpha Test
uniform bool u_alpha_test;
// Fog
uniform bool u_fog;
uniform vec4 u_fog_color;
uniform bool u_fog_is_linear;
uniform float u_fog_start;
uniform float u_fog_end;
varying vec4 v_fog_eye_position;
// Main
void main(void) {
gl_FragColor = v_color;
// Texture
if (u_has_texture) {
gl_FragColor *= texture2D(u_texture_unit, v_texture_pos.xy);
}
// Alpha Test
if (u_alpha_test && gl_FragColor.a <= 0.1) {
discard;
}
// Fog
if (u_fog) {
float fog_factor;
if (u_fog_is_linear) {
fog_factor = (u_fog_end - length(v_fog_eye_position)) / (u_fog_end - u_fog_start);
} else {
fog_factor = exp(-u_fog_start * length(v_fog_eye_position));
}
gl_FragColor = mix(gl_FragColor, u_fog_color, 1.0 - clamp(fog_factor, 0.0, 1.0));
}
}

Some files were not shown because too many files have changed in this diff Show More