Compare commits

..

246 Commits

Author SHA1 Message Date
Tschipp
de388366ca Updated Version 2025-12-31 09:57:34 +01:00
Tschipp
b66040bf03 Fixed wrong Packet ID for Carry Data Sync on Forge, Proper handling of carried player dying 2025-12-29 23:27:04 +01:00
Tschipp
47910dbf61 Added possibility for scripts to override certain pickup checks. Closes #853 2025-12-29 23:23:28 +01:00
Tschipp
f147e801cc Updated to 1.21.11 2025-12-27 23:25:58 +01:00
Tschipp
20a40c1487
Update issue templates 2025-12-27 23:00:46 +01:00
Tschipp
08bc465d82 Fixed bugs, updated Blacklist 2025-12-26 15:56:13 +01:00
Tschipp
3352c497e2 Merge branch 'CatsSomeCat-1.21.8' into 1.21.9 2025-12-25 16:30:41 +01:00
Tschipp
f58829ea21 Merge branch '1.21.8' of github.com:CatsSomeCat/CarryOn into CatsSomeCat-1.21.8
# Conflicts:
#	Common/src/main/java/tschipp/carryon/common/carry/PlacementHandler.java
#	Fabric/src/main/java/tschipp/carryon/CarryOnFabricMod.java
#	Fabric/src/main/java/tschipp/carryon/events/CommonEvents.java
#	gradle.properties
2025-12-25 16:29:06 +01:00
Tschipp
550940b4ab Fixed Sync Issue after Respawning #850 #845 #843 2025-12-25 14:19:05 +01:00
Tschipp
4ca8a885da Cleaned up fork code, restored carry transformations 2025-12-24 22:29:30 +01:00
Tschipp
326880d40b Merge branch 'Hanro50-1.21.9' into 1.21.9 2025-12-23 11:53:20 +01:00
Tschipp
d4e0b29a06 Merge branch '1.21.9' of github.com:Hanro50/CarryOn into Hanro50-1.21.9
# Conflicts:
#	Common/src/main/java/tschipp/carryon/CarryOnCommon.java
#	Common/src/main/java/tschipp/carryon/CarryOnCommonClient.java
#	Common/src/main/java/tschipp/carryon/client/keybinds/ConflictFreeKeyMapping.java
#	Common/src/main/java/tschipp/carryon/client/render/CarriedObjectRender.java
#	Common/src/main/java/tschipp/carryon/mixin/AvatarRenderStateMixin.java
#	Common/src/main/java/tschipp/carryon/mixin/HumanoidModelMixin.java
#	Common/src/main/resources/carryon.mixins.json
#	Fabric/build.gradle
#	build.gradle
#	gradle.properties
2025-12-23 11:51:53 +01:00
Tschipp
8d8e0dad82 Initial work on 1.21.9 2025-11-23 20:40:31 +01:00
Hanro50
e1e122ae9b Fixed crash with mannequin 2025-10-25 09:53:14 +02:00
Hanro50
69eb806228 code cleanup 2025-10-25 09:05:48 +02:00
Hanro50
08b2a41043 Fixed 3rd person rendering 2025-10-24 22:27:31 +02:00
Hanro50
6f0c20077a Update CommonEvents.java 2025-10-22 19:42:01 +02:00
Hanro50
21f09b2526 Update CommonEvents.java 2025-10-22 19:37:26 +02:00
Hanro50
9a484df16e Fixed bugs related to picking up players
- Fixed slowness getting stuck when the other player dismounted with shift
- Fixed bug where player couldn't press shift to dismount
- Fixed being unable to place other player back down
2025-10-16 07:50:31 +02:00
Hanro50
e79e52cf65 Update PickupHandler.java 2025-10-15 22:03:53 +02:00
Hanro50
d35cb4ed72 Bug fixes
- Ports fabric disconnect fix to neoforge
- Fixes console error when trying to pickup non owned tamable mobs.
2025-10-15 22:03:28 +02:00
Hanro50
5cf2e87fe8 Update CarryOnFabricMod.java 2025-10-15 21:52:23 +02:00
Hanro50
ef8362e728 Update CarryOnFabricMod.java 2025-10-15 21:51:52 +02:00
Hanro50
e3be9c84da Revert "confusing "and" and for an "or""
This reverts commit efdd3277cc.
2025-10-15 21:18:32 +02:00
Hanro50
efdd3277cc confusing "and" and for an "or" 2025-10-15 19:23:41 +02:00
Hanro50
776d079be0 forge fix 2025-10-15 09:47:48 +02:00
Hanro50
9d6ffc37ca Fixes kick on death on neoforge 2025-10-15 09:11:08 +02:00
Hanro50
af25f681be fixes the kick on respawn bug 2025-10-15 08:27:25 +02:00
Hanro50
98247bceb2 Update ClientEvents.java 2025-10-15 08:18:23 +02:00
Hanro50
41b518942d Update CarryOnRenderType.java 2025-10-15 08:16:00 +02:00
Hanro50
32db7222b7 Swear I did fix this 2025-10-15 08:07:18 +02:00
Hanro50
eadfba05e8 some mild work on porting to 1.21.9 2025-10-15 07:51:47 +02:00
ElysianCat
00c0c89858 Bump to 2.7.1: fix slot selection and AttachmentType crash
- Fixed slot selection conflict with Sounds mod that caused rapid sound spam.
- Resolved crash-on-death bug triggered by AttachmentType handling.
- Improved Carry On slot change logic for stability and compatibility.
- Updated project version from 2.7.0 → 2.7.1.
2025-09-23 23:50:26 +03:30
ElysianCat
59ecfa81e5 Merge branch 'fix/crash-on-death-1.21.8' into 1.21.8 2025-09-23 23:45:10 +03:30
ElysianCat
c4346a4c00 Refactor CarryOn functionality to improve slot selection logic. Ensure that inventory slot changes are only allowed when not carrying an item. 2025-09-23 23:43:03 +03:30
ElysianCat
3fddd1112b Add ClientboundSyncCarryDataPacket for syncing carry data and enhance carry handling on player death
- Introduced ClientboundSyncCarryDataPacket to manage carry data synchronization between server and client.
- Updated PlacementHandler to handle carry data transfer during player death scenarios, considering keepInventory game rule.
- Refactored carry data handling in CommonEvents to ensure proper transfer and clearing of carry data on player respawn.
- Registered the new packet in CarryOnCommon for clientbound communication.
2025-09-23 23:32:49 +03:30
Tschipp
ece3ed7ff2 Updated to 1.21.8. Changed Data Storage to use Attachments or Capabilities. 2025-09-01 10:18:25 +02:00
Tschipp
162fc1051d Updated to 1.21.7 2025-08-25 10:49:14 +02:00
Tschipp
e7bf9a4dee Updated to 1.21.6 2025-08-16 22:02:28 +02:00
Tschipp
7f6e41e36a Blacklisted expanded Storage 2025-07-26 09:20:45 +02:00
Texaliuz
d9d25ab598 Translation into Argentine Spanish (es_ar) for CarryOn
Hello, I would appreciate if you could add the translation to my language (es_ar) for version 1.21.1 please and thank you.
2025-07-26 00:44:24 +02:00
inceon
9b2103137f Added uk_ua.json for Ukrainian localization 2025-07-26 00:44:14 +02:00
Bayi
7fc80adfe0 Add lang **hu_hu** 2025-07-26 00:44:02 +02:00
Tschipp
c662995320 Updated Version Numbers 2025-07-26 00:39:54 +02:00
Tschipp
0dec5bb175 Fixed various Bugs 2025-07-26 00:39:32 +02:00
Tschipp
1194370405 Updated Configs 2025-07-26 00:37:35 +02:00
Tschipp
45a2b32c97 Fixed Player Carrying, closes #774 2025-07-22 23:48:52 +02:00
Tschipp
d1227d3d87 Updated to 1.21.5 2025-07-08 10:51:36 +02:00
Tschipp
60594ea3bc Updated default Blacklist 2025-04-21 23:47:53 +02:00
Tschipp
03c2b1fe1c
Merge pull request #744 from wajo21x/1.21
Added translation to Spanish (Ecuador).
2025-04-21 23:46:09 +02:00
Tschipp
43012f8462 Updated default Blacklist, Fixed Cloth Config compat with saving 2025-04-21 13:19:54 +02:00
Tschipp
24c15ffb7b Updated version, fixed 1.21.4 2025-04-20 23:40:51 +02:00
Tschipp
67db9798d8 started work on mod event hooks 2025-02-03 14:31:25 +01:00
wajo21x
a2362104fc Added translation to Spanish (Ecuador).
es_ec
2025-02-03 08:29:06 -05:00
Tschipp
5cff7411cb
Merge pull request #726 from Aresiel/patch-1
Forbid "You're in Grave Danger"'s blocks from being picked up
2025-02-02 14:08:27 +01:00
Aresiel
c803de7920
Forbid "You're in Grave Danger"'s blocks from being picked up 2025-01-07 19:55:44 +01:00
Tschipp
dd149b2472 Fixed forge server crash 2025-01-05 18:07:10 +01:00
Tschipp
ae260556b2 Updated to 1.21.4, Added support for Cloth Config 2025-01-04 00:32:09 +01:00
Tschipp
7251cbf03f Fixed crash on launch on Forge 2024-12-29 13:54:55 +01:00
Tschipp
230692baf6 Updated default Blacklist 2024-12-28 20:23:09 +01:00
Tschipp
be105218fb
Merge pull request #685 from konumatakaki/1.21
Addition of Japanese translation
2024-12-28 16:41:36 +01:00
Tschipp
58b0e8fef0
Merge pull request #701 from Hexasan/patch-1
Update Turkish Translation
2024-12-28 16:17:54 +01:00
Tschipp
93633a05bb
Merge pull request #706 from TKsMods/1.21
add german translation de_de.json
2024-12-28 16:17:06 +01:00
Tschipp
0b46e57a92
Merge pull request #678 from Tracktark/patch-1
Add minecraft:interaction to entity blacklist
2024-12-28 16:05:55 +01:00
Tschipp
1b65095902
Merge pull request #708 from NumberSir/patch-1
Create zh_cn.json
2024-12-28 13:03:27 +01:00
Tschipp
d653814af9
Merge pull request #714 from ImHoppy/ImHoppy-patch-1 2024-12-28 11:07:02 +01:00
Tschipp
38688ffb85
Merge pull request #713 from hugoalh/lang/zh_tw
Add lang `zh_tw`
2024-12-28 11:01:14 +01:00
Tschipp
058b547c30 Updated to 1.21.3 2024-12-27 18:25:03 +01:00
Hoppy
01cacce7df
Blacklist LittleTiles mod
Picking up a block from this mod can cause a crash loop due to excessive data
2024-12-01 18:14:46 +01:00
hugoalh
7ba95504a6
Add lang zh_tw 2024-11-30 17:14:43 +08:00
Number_Sir
74806d011b
Create zh_cn.json 2024-11-14 04:10:31 +08:00
Tristan Kechlo
c292eed7af add de_de.json 2024-11-07 20:49:20 +01:00
Hexasan
9b1e131641
Update Turkish Translation
-update tr_tr.json
-fixed the mistakes the other guy made
2024-11-02 23:19:09 +03:00
Konuma Takaki
5958fa43c1
Addition of Japanese translation
Japanese translation files (ja_jp.json) added
(This is a redo of #669.)
2024-09-14 14:44:26 +09:00
Tracktark
a622cf0452
Add minecraft:interaction to entity blacklist 2024-08-27 17:34:14 +02:00
Tschipp
d3ab092d4f fixed build pipeline (hopefully) 2024-08-21 09:56:53 +02:00
Tschipp
9a5b09136f changed build.gradle 2024-08-19 12:04:15 +02:00
Tschipp
8b96dab42b changed build.gradle 2024-08-19 11:27:20 +02:00
Tschipp
5271a82b9f changed build.gradle 2024-08-19 11:10:14 +02:00
Tschipp
a4843857cd Updated to 1.21.1 2024-08-19 10:58:36 +02:00
Tschipp
2a9a8703d4 fixed neoforge crashing on load 2024-07-17 23:34:36 +02:00
Tschipp
2be47d8d53 fixed fabric servers not being joinable 2024-07-17 22:31:57 +02:00
Tschipp
742a9f0ebc fixed fabric servers not being joinable 2024-07-17 22:31:36 +02:00
Tschipp
dd9964b7b2 Updated to 1.21 2024-07-14 23:57:55 +02:00
Tschipp
753f19e7b0 Updated to 1.21 2024-07-14 15:35:40 +02:00
Tschipp
3cfb59b70a
Merge pull request #647 from thatTopHatCat/patch-1
Added items from Cuffed to blacklist
2024-07-10 21:33:02 +02:00
Tschipp
02d3b110a3
Merge branch '1.20' into patch-1 2024-07-10 21:32:50 +02:00
Tschipp
2830bb3a65
Merge pull request #640 from smoong951/1.20
Update ko_kr.json
2024-07-10 21:31:36 +02:00
Tschipp
3fd4c92822 fixed build 2024-07-10 21:31:01 +02:00
Tschipp
d64aaea8f9 updated Jenkinsfile 2024-07-09 23:50:54 +02:00
Tschipp
032c1a943a updated configs 2024-07-09 23:47:22 +02:00
Wheelbarrow
43d990a4db
Added items from Cuffed to blacklist
you could pick up padlocks lmao
2024-07-07 17:54:11 -04:00
Tschipp
8cc0424d46 1.20.6 works, except for forge 2024-06-28 13:02:53 +02:00
Tschipp
b574f5b509 started work on 1.20.6 2024-06-23 20:28:08 +02:00
smoong
5750880473
Update ko_kr.json 2024-06-24 00:00:02 +09:00
Tschipp
75ca33bb8d updated Jenkinsfile 2024-02-27 22:47:33 +01:00
Tschipp
196ffb03bf updated build.gradle 2024-02-27 22:34:04 +01:00
Tschipp
08804d435d updated build.gradle, config 2024-02-27 22:14:43 +01:00
Tschipp
2f2a4a6ca5 Added proper copyright notice 2024-02-27 22:02:35 +01:00
Tschipp
5fb444a92c Fixed tags not loading, updated configs 2024-02-26 23:25:16 +01:00
Tschipp
aa6ba82ae5 Updated to 1.20.4, added NeoForge 2024-02-25 17:53:24 +01:00
Tschipp
0d9e6cf32e Fixed memory leak, crash with Rats, now compatible with newer forge versions. 2023-11-19 23:00:43 +01:00
Tschipp
be7c5e891e
Merge pull request #560 from ZEROX7/patch-1
Update mods.toml
2023-11-19 21:52:55 +01:00
ZEROX7
3ee6f8d56a
Update mods.toml
fixes not working with newer forges
2023-10-02 18:21:22 +02:00
Tschipp
dbb7e59b21 should be compatible on 1.20 2023-08-30 22:08:00 +02:00
Tschipp
68341b7ff1 Fixed various bugs relating to placement 2023-08-30 22:01:43 +02:00
Tschipp
a5366a9a2f no longer includes amecs 2023-07-25 14:08:32 +02:00
Tschipp
5efb509aea Fixed crash with amecs 2023-07-07 09:50:03 +02:00
Tschipp
ddbd9d3d84 Update to 1.20.1 2023-07-06 18:48:28 +02:00
Tschipp
e44ff0ea5b Fixed IMC, Keybinds, other bugs 2023-07-06 17:11:12 +02:00
Tschipp
0f22c9650f Merge remote-tracking branch 'origin/1.19-multiloader' into 1.19-multiloader
# Conflicts:
#	Fabric/build.gradle
2023-07-06 17:10:47 +02:00
Tschipp
5c460996ae Fixed IMC, Keybinds, other bugs 2023-07-06 17:06:47 +02:00
Tschipp
6c30e82dc5
Merge pull request #521 from alpeerkaraca/1.19-multiloader
Add tr_tr.json!
2023-07-04 19:42:57 +02:00
Alper Karaca
1d29f99e7c
Add tr_tr.json! 2023-07-04 18:55:35 +03:00
Tschipp
80899ad999
updated MixinExtras 2023-04-28 22:11:36 +02:00
Tschipp
dafcf0c0c2 Merge remote-tracking branch 'origin/1.19-multiloader' into 1.19-multiloader
# Conflicts:
#	Common/src/main/java/tschipp/carryon/common/config/CarryConfig.java
2023-04-24 22:27:25 +02:00
Tschipp
2cbff25e0c Updated to 1.19.4, fixed bugs 2023-04-24 22:24:54 +02:00
Tschipp
f330646b9d
Merge pull request #478 from Meowlala/1.19-multiloader
Config option for picking unbreakable blocks in Survival
2023-04-24 13:54:31 +02:00
Tschipp
50d47ab650
Merge pull request #469 from MarkusBordihn/patch-2
[1.19] Added easy_npc entities to the forbiddenEntities list.
2023-04-24 13:53:50 +02:00
Meowlala
a5b619a77c Config option for picking unbreakable blocks in Survival
This was supported in earlier versions of CarryOn, and has some use cases, e.g. moving BetterEnd's eternal pedestals.

Off by default, simply disables the destroySpeed check when picking up a block.

Best combined with a whitelist.
2023-03-21 11:13:40 -05:00
Markus Bordihn
b1e6ea2865
Update CarryConfig.java 2023-02-25 02:18:10 +01:00
Markus Bordihn
7cd979d3e7
Added easy_npc entities to the forbiddenEntities list. 2023-02-25 00:38:21 +01:00
Tschipp
1e1324bcde Fixed MixinExtras by using JarJar 2023-02-01 21:04:16 +01:00
Tschipp
b684df06fa
Update issue_template.md 2023-01-29 19:03:01 +01:00
Tschipp
7aacc4a524
Merge pull request #454 from Tschipp/1.19.2
Fixed shadowing of mixinextras, added french translation
2023-01-26 23:01:59 +01:00
Tschipp
edd98a10f7
Merge branch '1.19-multiloader' into 1.19.2 2023-01-26 23:01:48 +01:00
Tschipp
efe2aef40b Fixed shadowing of mixinextras, added french translation 2023-01-26 22:59:14 +01:00
Tschipp
d8d9427e60
Merge pull request #453 from Calvineries/patch-1
Create fr_fr.json
2023-01-25 20:04:28 +01:00
Calvineries
67b114149e
Create fr_fr.json 2023-01-21 09:42:22 +01:00
Tschipp
3492b4d52b
Merge pull request #451 from Tschipp/1.19.2
Latest updates
2023-01-18 21:59:20 +01:00
Tschipp
5249002c2c
Merge branch '1.19-multiloader' into 1.19.2 2023-01-18 21:59:11 +01:00
Tschipp
3339a68564 Fixed multiple render crashes, fixed fabric config loading, improved mixin compatibility 2023-01-18 21:49:31 +01:00
Tschipp
6da53ee543
Merge pull request #444 from wilsontulus/patch-1
Blacklist all SecurityCraft stuff by default
2023-01-07 15:22:43 +01:00
Wilson Simanjuntak
e836734ca8
Blacklist all SecurityCraft stuff by default
Blacklist all SecurityCraft entities and blocks by default, because they're designed to be unbreakable except by their "owner(s)".
2023-01-06 13:38:45 +07:00
Tschipp
9d934e8d90
Bumped Version 2022-12-30 15:32:54 +01:00
Tschipp
1bb75a9b8e Bumped Version 2022-12-30 15:32:32 +01:00
Tschipp
b0ba88be5e
Merge pull request #442 from Tschipp/1.19.2
Added FirstPersonRender compat, augmented blacklist, fixed mixin conflict issue
2022-12-30 15:30:49 +01:00
Tschipp
ce00fa1f85 Added FirstPersonRender compat, augmented blacklist, fixed mixin conflict issue 2022-12-30 15:28:47 +01:00
Tschipp
209a976d4f Fixed Mixin 2022-12-17 15:51:56 +01:00
Tschipp
3c516a650f Merge remote-tracking branch 'origin/1.19-multiloader' into 1.19-multiloader 2022-12-17 15:39:20 +01:00
Tschipp
3f61e6c5a9 Updated to 1.19.3, made dependency on Gamestages less strict 2022-12-17 15:38:59 +01:00
Tschipp
b77e9ddd10
Update README.md 2022-12-12 11:19:20 +01:00
Tschipp
78402e9cc7 Fixed fabric build 2022-12-10 21:58:46 +01:00
Tschipp
e306fdce7d Deleted old 2022-12-10 18:43:42 +01:00
Tschipp
49f3990eee Fixed bugs 2022-12-10 18:28:21 +01:00
Tschipp
2d24b3d8ce Changed Jenkinsfile 2022-12-05 00:47:46 +01:00
Tschipp
555b484c1a Changed Jenkinsfile 2022-12-05 00:41:57 +01:00
Tschipp
191ce26ee4 Added final config options. Added gamestages support. Fixed rendering issues 2022-12-05 00:17:48 +01:00
Tschipp
375eb8dcc3 Added networking, Scripting 2022-11-29 00:49:57 +01:00
Tschipp
cf6a14f5d9 More updates to joint fabric-forge build 2022-11-16 09:31:55 -08:00
Tschipp
e6ace77c39 Further progress with rewrite 2022-10-11 22:25:56 +02:00
Tschipp
44a1d33f0f Started work on rewrite, using Multiloader 2022-10-03 13:43:38 +02:00
Tschipp
02c5376979 Updated to 1.18.2 2022-03-05 16:50:08 +01:00
Tschipp
b462098acf
Merge pull request #363 from YourPulse/patch-1
Added 1.18 support
2022-01-10 10:00:57 +01:00
Alex
b2e2070433
Added 1.18 support
Now it's able to work on 1.18 minecraft
2022-01-09 00:38:19 +03:00
Tschipp
cc70ed906b fixed boats and minecarts 2021-12-25 00:17:44 +01:00
Tschipp
28c4d4a2f9 Fixed blocks not saving data 2021-12-24 23:54:33 +01:00
Tschipp
df6498a236 updated jenkinsfile 2021-12-23 23:10:17 +01:00
Tschipp
a84cc85fdb Updated to 1.18 2021-12-23 22:59:20 +01:00
Tschipp
0d7aa01233 added russian translation 2021-12-23 17:27:26 +01:00
Tschipp
50019a4f94 fixed javadoc 2021-12-23 17:20:29 +01:00
Tschipp
6d85b42903 Fixed block lighting 2021-12-23 17:17:02 +01:00
Tschipp
ff15f45ea0 cleaned up some code 2021-12-21 11:00:11 +01:00
Tschipp
3a8d938136 Worked on 1.17 branch, still has block lighting bug 2021-12-21 09:37:00 +01:00
Tschipp
61aba0c6a0
Merge pull request #323 from jaredlll08/patch-1
Future proof Jenkinsfile
2021-06-12 15:05:16 +02:00
Jared
bb9c321a42
Future proof Jenkinsfile 2021-06-12 03:52:27 +02:00
Tschipp
c2e567e27e fixed crash 2021-06-05 23:09:18 +02:00
Tschipp
5e8ce8fc79 Updated to official mappings, enhanced entity rendering 2021-06-05 21:37:19 +02:00
Tschipp
80adff0ce3 Merge remote-tracking branch 'origin/1.16' into 1.16 2021-02-17 00:49:04 +01:00
Tschipp
a5529fe730 . 2021-02-17 00:49:01 +01:00
Tschipp
9643947f0f (hopefully) fixed config reloading now 2021-02-17 00:47:09 +01:00
Tschipp
97c2f4f8a1
Merge pull request #289 from Gamma5oo/1.16
add my translation into Italian
2021-02-16 23:28:25 +01:00
Gamma5oo
9bbb1990a9
Add files via upload 2021-02-16 14:44:44 +01:00
Tschipp
07e5153c40 Fixed configs not synching properly, added spanish translation 2021-02-16 10:48:24 +01:00
Tschipp
af1012d7a3 Removed #mekanism_cardboard_blacklist from the blacklist 2021-02-15 17:47:45 +01:00
Tschipp
439e4f05ca Merge remote-tracking branch 'origin/1.16' into 1.16 2021-02-15 17:21:50 +01:00
Tschipp
3d4dab6619 Readded Obfuscate and Gamestage support, fixed several bugs 2021-02-15 17:21:46 +01:00
Tschipp
171abb8210
Merge pull request #273 from othuntgithub/1.16
Create ko_kr.json
2020-12-30 11:41:53 +01:00
오예
de2c5326c6 create ko_kr.json 2020-12-30 12:24:41 +09:00
Tschipp
1ece990eb0 Updated default configs 2020-10-13 22:23:33 +02:00
Tschipp
bea813023c Updated to 1.16.3 2020-10-06 13:36:19 +02:00
Tschipp
894568d64a test 2020-09-08 00:32:58 +02:00
Tschipp
4528be263e
Update README.md 2020-09-07 14:38:08 +02:00
Tschipp
b470478a40 Finalized port to 1.16 2020-09-07 13:55:56 +02:00
Tschipp
c8e79860ad Port to 1.16 2020-09-06 23:55:49 +02:00
Tschipp
ceed903993 Started work on Script Reload Listener 2020-09-06 18:33:26 +02:00
Tschipp
2820c9fb3b Updated props 2020-09-06 17:22:25 +02:00
Tschipp
c03fab7b19 Fixed Chest placement 2020-09-06 17:20:59 +02:00
Tschipp
63d7b6dec8 Updated to 1.15 2020-09-06 17:12:05 +02:00
Tschipp
fe6a41e3f3 Updated to 1.14.4 2019-09-15 13:26:53 +02:00
Unknown
b34e09a387 Start 1.14 update 2019-07-29 09:46:03 +02:00
Tschipp
65d3f58eaa Update to 1.13.2 2019-03-23 22:59:49 +01:00
Tschipp
cb5edc3061 Obfuscate Support 2018-12-05 18:48:38 +01:00
Tschipp
d3fb8efb45 Update to 1.11.1 2018-10-05 15:40:01 +02:00
Tschipp
4e30e55f3a Merge remote-tracking branch 'origin/1.12' into 1.12 2018-08-14 23:38:54 +02:00
Tschipp
cda44221f7 #124, #125, #126, #127, #128, #129 2018-08-14 23:37:50 +02:00
Unknown
29a9cffe8c Added things to blacklist and fixed Gui close issue 2018-08-03 17:50:49 +02:00
Tschipp
bca7534257 Stupid Config Mistake 2018-07-23 00:46:12 +02:00
Tschipp
eff9e1ba21 mcmod.info 2018-07-23 00:35:38 +02:00
Tschipp
149fe1978e [1.12.2] Added thaumcraft to blacklist, redone arm rendering 2018-07-23 00:29:02 +02:00
Tschipp
9025c53a35 Merge branch 'master' into 1.12 2018-07-06 16:38:23 +02:00
Tschipp
66d7af98d8 Added Protection for Entities [1.12] 2018-07-06 16:33:32 +02:00
Tschipp
324b055dea Updated to the lastest version of Gamestages [1.12.2] 2018-07-06 11:36:08 +02:00
Tschipp
5ac582566d Merge branch 'master' into 1.12 2018-05-11 23:26:40 +02:00
Tschipp
d3e844e6b3 Mcmod.info [1.12.2] 2018-05-11 20:14:52 +02:00
Tschipp
934e36ada8 Merge branch 'master' into 1.12 2018-05-11 20:05:41 +02:00
Tschipp
97433722fd Updated FTBUtils 1.12 2018-05-11 20:05:24 +02:00
Tschipp
38cf3d6df3 Merge branch 'master' into 1.12 2018-03-24 11:25:39 +01:00
Tschipp
f0bb82ddc8 Fixed comp. issue with ftbu and betterplacement 2018-02-08 15:02:26 +01:00
Tschipp
3dbd7deb84 Merge branch 'master' into 1.12 2018-01-24 17:03:28 +01:00
Tschipp
5ccc660fef Merge branch 'master' into 1.12 2017-11-04 11:39:23 +01:00
Tschipp
6884452534 MCVersion 2017-11-04 11:35:15 +01:00
Tschipp
7c950301bb Merge branch 'master' into 1.12 2017-11-04 11:35:06 +01:00
Tschipp
d8647e8ab8 Update to latest FTBUtils 2017-11-04 09:38:38 +01:00
Tschipp
4daed35785 Merge branch 'master' into 1.12 2017-10-07 18:29:32 +02:00
Tschipp
3018400e00 Merge branch 'master' into 1.12 2017-10-03 17:05:16 +02:00
Tschipp
c2f348b209 Merge branch 'master' into 1.12 2017-10-03 16:45:30 +02:00
Tschipp
88794b0986 1.12 Rotation change... 2017-10-01 19:39:21 +02:00
Tschipp
2ea5ad18d3 Merge branch 'master' into 1.12 2017-10-01 19:29:01 +02:00
Tschipp
33309b1114 Merge branch 'master' into 1.12 2017-10-01 19:24:50 +02:00
Tschipp
275cf81593 Scripting Part 1 2017-10-01 19:24:37 +02:00
Tschipp
732e3b48b2 Thing 2017-09-28 20:25:09 +02:00
Tschipp
da3e2b42ea Merge branch 'master' into 1.12 2017-09-18 17:05:16 +02:00
Tschipp
dad395fd39 Merge branch 'master' into 1.12 2017-09-17 22:07:46 +02:00
Tschipp
1fe9f3920e Update to 1.5 2017-09-17 19:14:23 +02:00
Tschipp
109dbb92c6 Merge remote-tracking branch 'origin/1.12' into 1.12 2017-09-12 23:59:47 +02:00
Tschipp
424c699f66 Artifacts 2017-09-12 23:59:41 +02:00
Tschipp
24ca37414d Merge pull request #32 from awwolfe/master
Added gameplay options
2017-09-12 23:57:01 +02:00
Tony Wolfe
e9f9a1f1d6 added whitelist, allow babies 2017-09-11 19:15:16 -05:00
Tony Wolfe
4d03f52ac2 initial 2017-09-11 18:00:39 -05:00
Tschipp
77058317cd Merge branch 'master' into 1.12 2017-09-04 18:35:23 +02:00
Tschipp
7dc848f891 Merge branch 'master' into 1.12 2017-09-03 18:32:07 +02:00
Tschipp
b4532bd9fa update to 1.3 2017-08-27 22:50:06 +02:00
Tschipp
386cd5d2f6 Merge branch 'master' into 1.12 2017-08-27 22:39:01 +02:00
Tschipp
b59cbd0a25 build.gradle 2017-08-20 01:10:32 +02:00
Tschipp
10ea3ae8ea Update to 1.2 2017-08-20 01:10:16 +02:00
Tschipp
6f3fb079c9 Arm sneak rotation 1.12 2017-08-20 00:28:21 +02:00
Tschipp
44e1804527 Fixed Crash 2017-08-15 14:30:49 +02:00
Tschipp
09bcf55da7 Changed Version Number 2017-08-15 14:26:31 +02:00
Tschipp
89961312c9 Merge branch 'master' into 1.12 2017-08-15 14:25:31 +02:00
Tschipp
ca5515cf5b renderArm 2017-08-14 23:00:08 +02:00
Tschipp
b69c05fcc2 Merge branch 'master' into 1.12 2017-08-14 22:59:14 +02:00
Tschipp
b1d91bf29d Merge branch 'master' into 1.12 2017-08-14 14:54:06 +02:00
Tschipp
ebf6f928bc Fixed Keybinds 2017-08-14 11:12:54 +02:00
Tschipp
c48aeceae4 Merge branch '1.12dev' into 1.12 2017-08-14 09:55:59 +02:00
Tschipp
19b4a4ebd8 Update to 1.12 2017-08-14 09:53:45 +02:00
184 changed files with 10509 additions and 2903 deletions

15
.gitattributes vendored Normal file
View File

@ -0,0 +1,15 @@
* text eol=lf
*.bat text eol=crlf
*.patch text eol=lf
*.java text eol=lf
*.gradle text eol=crlf
*.png binary
*.gif binary
*.exe binary
*.dll binary
*.jar binary
*.lzma binary
*.zip binary
*.pyd binary
*.cfg text eol=lf
*.jks binary

View File

@ -0,0 +1,22 @@
---
name: Blacklist Request
about: Have a block / entity that shouldn't be picked up by Carry On? Report it here.
title: "[Blacklist]"
labels: Blacklist
assignees: ''
---
**Describe the problem**
What block / entity is causing issues? What problems occur with placement / pickup?
**ID's to Blacklist**
List of block identifiers (namespace:name) to blacklist. You can find identifiers by activating F3 and moving your crosshair over the block
-
-
...
**Game Information (please complete the following information):**
- Minecraft Version:
- Mod Loader:
- Carry On Version:

28
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,28 @@
---
name: Bug report
about: Create a report about a crash or otherwise buggy behavior
title: "[Bug]"
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1.
2.
...
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Game Information (please complete the following information):**
- Minecraft Version:
- Mod Loader:
- Carry On Version:
**Additional context, logs**
Add any other context about the problem here. Also include logs if available

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for Carry On
title: "[Feature Request]"
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

43
.gitignore vendored
View File

@ -1,24 +1,3 @@
# gradle
.gradle/
build/
out/
bin/
# idea
.idea/
*.iml
*.ipr
*.iws
#vscode
.vscode/
.project
.classpath
# eclipse
bin
*.launch
@ -26,7 +5,23 @@ bin
.metadata
.classpath
.project
.DS_Store
# fabric
run/
# idea
out
*.ipr
*.iws
*.iml
.idea/*
!.idea/scopes
# gradle
build
.gradle
# other
eclipse
run
runs
# vscode
.vscode/*

51
Common/build.gradle Normal file
View File

@ -0,0 +1,51 @@
plugins {
id 'multiloader-common'
id 'net.neoforged.moddev'
}
repositories {
maven {
name = "Shedaniel"
url "https://maven.shedaniel.me/"
}
maven { url 'https://jitpack.io' }
}
neoForge {
neoFormVersion = neo_form_version
// Automatically enable AccessTransformers if the file exists
def at = file('src/main/resources/META-INF/accesstransformer.cfg')
if (at.exists()) {
accessTransformers.from(at.absolutePath)
}
parchment {
minecraftVersion = parchment_game_version
mappingsVersion = parchment_version
}
}
dependencies {
compileOnly group: 'org.spongepowered', name: 'mixin', version: '0.8.5'
// fabric and neoforge both bundle mixinextras, so it is safe to use it in common
implementation("io.github.llamalad7:mixinextras-common:${mixinextras_version}")
annotationProcessor("io.github.llamalad7:mixinextras-common:${mixinextras_version}")
compileOnly("me.shedaniel.cloth:cloth-config-neoforge:${cloth_config_version}")
}
configurations {
commonJava {
canBeResolved = false
canBeConsumed = true
}
commonResources {
canBeResolved = false
canBeConsumed = true
}
}
artifacts {
commonJava sourceSets.main.java.sourceDirectories.singleFile
commonResources sourceSets.main.resources.sourceDirectories.singleFile
}

View File

@ -0,0 +1,208 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon;
import com.mojang.brigadier.CommandDispatcher;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.RegistrySetBuilder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.common.carry.PlacementHandler;
import tschipp.carryon.common.command.CommandCarryOn;
import tschipp.carryon.config.ConfigLoader;
import tschipp.carryon.networking.clientbound.ClientboundStartRidingOtherPlayerPacket;
import tschipp.carryon.networking.clientbound.ClientboundStartRidingPacket;
import tschipp.carryon.networking.clientbound.ClientboundSyncScriptsPacket;
import tschipp.carryon.networking.serverbound.ServerboundCarryKeyPressedPacket;
import tschipp.carryon.platform.Services;
public class CarryOnCommon
{
public static final RegistrySetBuilder BUILDER = new RegistrySetBuilder();
public static HolderLookup.Provider createLookup() {
RegistryAccess.Frozen registryaccess$frozen = RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY);
HolderLookup.Provider holderlookup$provider = BUILDER.build(registryaccess$frozen);
return holderlookup$provider;
}
public static void registerServerPackets(Object... args)
{
Services.PLATFORM.registerServerboundPacket(
ServerboundCarryKeyPressedPacket.TYPE,
ServerboundCarryKeyPressedPacket.class,
ServerboundCarryKeyPressedPacket.CODEC,
ServerboundCarryKeyPressedPacket::handle,
args
);
}
public static void registerClientPackets(Object... args)
{
Services.PLATFORM.registerClientboundPacket(
ClientboundStartRidingPacket.TYPE,
ClientboundStartRidingPacket.class,
ClientboundStartRidingPacket.CODEC,
ClientboundStartRidingPacket::handle,
args
);
Services.PLATFORM.registerClientboundPacket(
ClientboundSyncScriptsPacket.TYPE,
ClientboundSyncScriptsPacket.class,
ClientboundSyncScriptsPacket.CODEC,
ClientboundSyncScriptsPacket::handle,
args
);
Services.PLATFORM.registerClientboundPacket(
ClientboundStartRidingOtherPlayerPacket.TYPE,
ClientboundStartRidingOtherPlayerPacket.class,
ClientboundStartRidingOtherPlayerPacket.CODEC,
ClientboundStartRidingOtherPlayerPacket::handle,
args
);
}
public static void registerConfig()
{
ConfigLoader.registerConfig(Constants.COMMON_CONFIG);
ConfigLoader.registerConfig(Constants.CLIENT_CONFIG);
}
public static void registerCommands(CommandDispatcher<CommandSourceStack> dispatcher)
{
CommandCarryOn.register(dispatcher);
}
public static void onCarryTick(ServerPlayer player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying())
{
// Dumb Fix to sync Carry Data after a respawn with KeepInventory, because we can't sync in the first tick.
if(player.tickCount == 1)
CarryOnDataManager.setCarryData(player, carry);
if(carry.getActiveScript().isPresent())
{
String cmd = carry.getActiveScript().get().scriptEffects().commandLoop();
if(!cmd.isEmpty())
player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
}
Inventory inv = player.getInventory();
inv.setSelectedSlot(carry.getSelected());
}
}
/**
* Returns true if the block can be broken.
*/
public static boolean onTryBreakBlock(Player player)
{
if (player != null && !Constants.COMMON_CONFIG.settings.hitWhileCarrying)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying())
return false;
}
return true;
}
/**
* Returns true of the entity can be attacked
*/
public static boolean onAttackedByPlayer(Player player)
{
if (player != null && !Constants.COMMON_CONFIG.settings.hitWhileCarrying)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying())
return false;
}
return true;
}
public static void onPlayerAttacked(Player player)
{
if (Constants.COMMON_CONFIG.settings.dropCarriedWhenHit && !player.level().isClientSide())
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (carry.isCarrying())
{
PlacementHandler.placeCarried((ServerPlayer) player);
}
}
}
public static void onRiderDisconnected(Player rider)
{
if(rider.getVehicle() instanceof ServerPlayer vehicle) {
CarryOnData data = CarryOnDataManager.getCarryData(vehicle);
if(data.isCarrying(CarryType.PLAYER)) {
PlacementHandler.placeCarried(vehicle);
}
}
}
public static int potionLevel(CarryOnData carry, Level level)
{
if(carry.isCarrying(CarryType.PLAYER))
return 1;
if(carry.isCarrying(CarryType.ENTITY))
{
Entity entity = carry.getEntity(level);
int i = (int) (entity.getBbHeight() * entity.getBbWidth());
if (i > 4)
i = 4;
if (!Constants.COMMON_CONFIG.settings.heavyEntities)
i = 1;
return (int) (i * Constants.COMMON_CONFIG.settings.entitySlownessMultiplier);
}
if(carry.isCarrying(CarryType.BLOCK))
{
String nbt = carry.getNbt().toString();
int i = nbt.length() / 500;
if (i > 4)
i = 4;
if (!Constants.COMMON_CONFIG.settings.heavyTiles)
i = 1;
return (int) (i * Constants.COMMON_CONFIG.settings.blockSlownessMultiplier);
}
return 0;
}
}

View File

@ -0,0 +1,67 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.client.keybinds.CarryOnKeybinds;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
public class CarryOnCommonClient
{
public static void checkForKeybinds()
{
Minecraft mc = Minecraft.getInstance();
Player player = mc.player;
if(player != null) {
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if ((CarryOnKeybinds.carryKey.isUnbound() ? player.isShiftKeyDown() : (CarryOnKeybinds.carryKey.isDown())) && !carry.isKeyPressed()) {
CarryOnKeybinds.onCarryKey(true);
carry.setKeyPressed(true);
CarryOnDataManager.setCarryData(player, carry);
} else if (!(CarryOnKeybinds.carryKey.isUnbound() ? player.isShiftKeyDown() : (CarryOnKeybinds.carryKey.isDown() ) ) && carry.isKeyPressed()) {
CarryOnKeybinds.onCarryKey(false);
carry.setKeyPressed(false);
CarryOnDataManager.setCarryData(player, carry);
}
}
}
public static void onCarryClientTick() {
Player player = Minecraft.getInstance().player;
if (player != null) {
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (carry.isCarrying()) {
int wantedSlot = carry.getSelected();
if (player.getInventory().getSelectedSlot() != wantedSlot) {
player.getInventory().setSelectedSlot(wantedSlot);
}
}
}
}
public static Player getPlayer()
{
return Minecraft.getInstance().player;
}
}

View File

@ -0,0 +1,43 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon;
import net.minecraft.resources.Identifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tschipp.carryon.common.config.CarryConfig;
public class Constants {
public static final String MOD_ID = "carryon";
public static final String MOD_NAME = "Carry On";
public static final Logger LOG = LoggerFactory.getLogger(MOD_NAME);
public static final CarryConfig.Common COMMON_CONFIG = new CarryConfig.Common();
public static final CarryConfig.Client CLIENT_CONFIG = new CarryConfig.Client();
public static final Identifier PACKET_ID_KEY_PRESSED = Identifier.fromNamespaceAndPath(Constants.MOD_ID, "key_pressed");
public static final Identifier PACKET_ID_START_RIDING = Identifier.fromNamespaceAndPath(Constants.MOD_ID, "start_riding");
public static final Identifier PACKET_ID_SYNC_SCRIPTS = Identifier.fromNamespaceAndPath(Constants.MOD_ID, "sync_scripts");
public static final Identifier PACKET_ID_START_RIDING_OTHER = Identifier.fromNamespaceAndPath(Constants.MOD_ID, "start_riding_other");
public static final Identifier PACKET_ID_SYNC_CARRY_ON_DATA = Identifier.fromNamespaceAndPath(Constants.MOD_ID, "sync_carry_data");
}

View File

@ -0,0 +1,51 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.client.keybinds;
import com.mojang.blaze3d.platform.InputConstants;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.KeyMapping.Category;
import net.minecraft.resources.Identifier;
import tschipp.carryon.Constants;
import tschipp.carryon.networking.serverbound.ServerboundCarryKeyPressedPacket;
import tschipp.carryon.platform.Services;
import java.util.function.Consumer;
public class CarryOnKeybinds
{
public static KeyMapping carryKey;
public static void registerKeybinds(Consumer<KeyMapping> registrar)
{
Category category = Category.register(Identifier.fromNamespaceAndPath(Constants.MOD_ID,"key.carry.category"));
carryKey = new KeyMapping("key.carry.desc", InputConstants.KEY_LSHIFT, category);
registrar.accept(carryKey);
}
public static void onCarryKey(boolean pressed)
{
Services.PLATFORM.sendPacketToServer(Constants.PACKET_ID_KEY_PRESSED, new ServerboundCarryKeyPressedPacket(pressed));
}
}

View File

@ -0,0 +1,136 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.client.modeloverride;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.DataResult;
import net.minecraft.commands.arguments.blocks.BlockStateParser;
import net.minecraft.commands.arguments.blocks.BlockStateParser.BlockResult;
import net.minecraft.commands.arguments.item.ItemParser;
import net.minecraft.commands.arguments.item.ItemParser.ItemResult;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Property;
import tschipp.carryon.common.scripting.Matchables.NBTCondition;
import javax.annotation.Nullable;
import java.util.Map;
public class ModelOverride {
private BlockResult parsedBlock;
private Either<ItemStack, BlockState> renderObject;
private ModelOverride(String raw, BlockResult parsedBlock, Type type, Either<ItemResult, BlockResult> parsedRHS)
{
this.parsedBlock = parsedBlock;
parsedRHS.ifLeft(res -> {
ItemStack stack = new ItemStack(res.item());
if(res.components() != null)
stack.applyComponents(res.components());
this.renderObject = Either.left(stack);
});
parsedRHS.ifRight(res -> {
BlockState state = res.blockState();
this.renderObject = Either.right(state);
});
}
public static DataResult<ModelOverride> of(String str, HolderLookup.Provider provider)
{
if(!str.contains("->"))
return DataResult.error(() -> str + " must contain -> Arrow!");
String[] split = str.split("->");
String from = split[0];
String to = split[1];
BlockResult res;
try {
res = BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK, from, true);
} catch (Exception e) {
return DataResult.error(() -> "Error while parsing " + from + ":" + e.getMessage());
}
Type type = Type.ITEM;
if(to.contains("(") && to.contains(")"))
{
String t = to.substring(to.indexOf("(") + 1, to.indexOf(")"));
if(t.equals("block"))
type = Type.BLOCK;
to = to.substring(to.indexOf(")") + 1);
}
Either<ItemResult, BlockResult> either;
try {
if(type == Type.ITEM)
either = Either.left(new ItemParser(provider).parse(new StringReader(to)));
else
either = Either.right(BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK, to, true));
}catch (CommandSyntaxException e) {
String finalTo = to;
return DataResult.error(() -> "Error while parsing " + finalTo + ":" + e.getMessage());
}
return DataResult.success(new ModelOverride(str, res, type, either));
}
public boolean matches(BlockState state, @Nullable CompoundTag tag)
{
if(state.getBlock() == parsedBlock.blockState().getBlock() && matchesProperties(state, parsedBlock.properties()))
{
if(tag == null || parsedBlock.nbt() == null)
return true;
NBTCondition nbt = new NBTCondition(parsedBlock.nbt());
return nbt.matches(tag);
}
return false;
}
public Either<ItemStack, BlockState> getRenderObject()
{
return this.renderObject;
}
private boolean matchesProperties(BlockState state, Map<Property<?>, Comparable<?>> props)
{
for(var entry : props.entrySet())
{
var val = state.getValue(entry.getKey());
if(val != entry.getValue())
return false;
}
return true;
}
public enum Type {
ITEM,
BLOCK
}
}

View File

@ -0,0 +1,72 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.client.modeloverride;
import com.mojang.serialization.DataResult;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.state.BlockState;
import tschipp.carryon.Constants;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class ModelOverrideHandler
{
private static List<ModelOverride> OVERRIDES = new ArrayList<>();
public static void initModelOverrides(HolderLookup.Provider provider)
{
OVERRIDES.clear();
for(String ov : Constants.CLIENT_CONFIG.modelOverrides)
{
addFromString(ov, provider);
}
}
public static Optional<ModelOverride> getModelOverride(BlockState state, @Nullable CompoundTag tag)
{
for(ModelOverride ov : OVERRIDES)
{
if(ov.matches(state, tag))
return Optional.of(ov);
}
return Optional.empty();
}
public static void addFromString(String str, HolderLookup.Provider provider)
{
DataResult<ModelOverride> res = ModelOverride.of(str, provider);
if(res.result().isPresent())
{
ModelOverride override = res.result().get();
OVERRIDES.add(override);
}
else
{
Constants.LOG.debug("Error while parsing ModelOverride: " + res.error().get().message());
}
}
}

View File

@ -0,0 +1,133 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.client.render;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.entity.state.EntityRenderState;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.renderer.rendertype.RenderTypes;
import net.minecraft.client.renderer.state.CameraRenderState;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptRender;
import tschipp.carryon.platform.Services;
public class CarriedObjectRender
{
public static boolean draw(Player player, PoseStack matrix, int light, float partialTicks,SubmitNodeCollector nodeCollector, boolean firstPerson)
{
if(Services.PLATFORM.isModLoaded("firstperson") || Services.PLATFORM.isModLoaded("firstpersonmod") || player == null)
return false;
CarryOnData carry = CarryOnDataManager.getCarryData(player);
try {
if (carry.isCarrying(CarryType.BLOCK))
drawBlock(player, matrix, light, CarryRenderHelper.getRenderState(player), nodeCollector, firstPerson, partialTicks);
else if (carry.isCarrying(CarryType.ENTITY))
drawEntity(player, matrix, light, partialTicks, nodeCollector, firstPerson);
}
catch (Exception e)
{
//hehe
}
if(carry.getActiveScript().isPresent())
{
ScriptRender render = carry.getActiveScript().get().scriptRender();
if(!render.renderLeftArm() && player.getMainArm() == HumanoidArm.LEFT)
return false;
if(!render.renderRightArm() && player.getMainArm() == HumanoidArm.RIGHT)
return false;
}
return carry.isCarrying();
}
private static void drawBlock(Player player, PoseStack matrix, int light, BlockState state, SubmitNodeCollector nodeCollector, boolean firstPerson, float partialTicks)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
ItemStackRenderState renderState = new ItemStackRenderState();
var layer = renderState.newLayer();
layer.setRenderType(RenderTypes.glint());
matrix.pushPose();
PoseStack renderPose = CarryRenderHelper.setupBlockTransformations(player, matrix, carry, firstPerson);
ItemStack renderStack = CarryRenderHelper.getRenderItemStack(player);
Minecraft.getInstance().getItemModelResolver().updateForTopItem(renderState, renderStack, ItemDisplayContext.NONE, player.level(), null, 0);
renderState.submit(renderPose, nodeCollector, light, OverlayTexture.NO_OVERLAY, 0);
matrix.popPose();
}
private static void drawEntity(Player player, PoseStack matrix, int light, float partialTicks,SubmitNodeCollector nodeCollector, boolean firstPerson) {
EntityRenderDispatcher manager = Minecraft.getInstance().getEntityRenderDispatcher();
Entity entity = CarryRenderHelper.getRenderEntity(player);
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (entity == null)
return;
Vec3 playerpos = CarryRenderHelper.getExactPos(player, partialTicks);
entity.setPos(playerpos.x, playerpos.y, playerpos.z);
entity.xRotO = 0.0f;
entity.yRotO = 0.0f;
entity.setYHeadRot(0.0f);
matrix.pushPose();
CarryRenderHelper.setupEntityTransformations(player, matrix, carry, firstPerson);
if (entity instanceof LivingEntity)
((LivingEntity) entity).hurtTime = 0;
try {
EntityRenderState renderState = manager.extractEntity(entity, 0);
renderState.shadowPieces.clear();
renderState.lightCoords = light;
manager.submit(renderState, new CameraRenderState(), 0, 0, 0, matrix, nodeCollector);
}
catch (Exception ignored)
{
}
matrix.popPose();
if(!firstPerson)
matrix.popPose();
}
}

View File

@ -0,0 +1,446 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.client.render;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import net.minecraft.client.Minecraft;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.ChestBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.TagValueInput;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.joml.Quaternionf;
import tschipp.carryon.Constants;
import tschipp.carryon.client.modeloverride.ModelOverride;
import tschipp.carryon.client.modeloverride.ModelOverrideHandler;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.common.scripting.CarryOnScript;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptRender;
import java.util.Optional;
public class CarryRenderHelper
{
public static Vec3 getExactPos(Entity entity, float partialticks)
{
return new Vec3(entity.xOld + (entity.getX() - entity.xOld) * partialticks, entity.yOld + (entity.getY() - entity.yOld) * partialticks, entity.zOld + (entity.getZ() - entity.zOld) * partialticks);
}
public static float getExactBodyRotationDegrees(LivingEntity entity, float partialticks)
{
if (entity.getVehicle() != null && entity.getVehicle() instanceof LivingEntity vehicle)
if(vehicle instanceof Player player)
return -(player.yBodyRotO + (player.yBodyRot - player.yBodyRotO) * partialticks);
else
return -(entity.yHeadRotO + (entity.yHeadRot - entity.yHeadRotO) * partialticks);
else
return -(entity.yBodyRotO + (entity.yBodyRot - entity.yBodyRotO) * partialticks);
}
public static Quaternionf getExactBodyRotation(LivingEntity entity, float partialticks)
{
return Axis.YP.rotationDegrees(getExactBodyRotationDegrees(entity, partialticks));
}
public static void applyGeneralTransformations(Player player, PoseStack matrix)
{
Pose pose = player.getPose();
matrix.pushPose();
matrix.scale(0.6f, 0.6f, 0.6f);
matrix.translate(0, 0, -1.35);
if (doSneakCheck(player))
{
matrix.translate(0, -0.4, 0);
}
if (pose == Pose.SWIMMING || pose == Pose.FALL_FLYING)
{
matrix.translate(0, 0, 2.5);
matrix.mulPose(Axis.XP.rotationDegrees(90));
}
matrix.translate(0, -0.5, 0.65);
}
public static PoseStack setupBlockTransformations(Player player, PoseStack matrix, CarryOnData carry, boolean firstPerson) {
if (firstPerson) {
matrix.scale(2.5f, 2.5f, 2.5f);
matrix.translate(0, -0.5, -1);
if (Constants.CLIENT_CONFIG.facePlayer != CarryRenderHelper.isChest(carry.getBlock().getBlock())) {
matrix.mulPose(Axis.YP.rotationDegrees(180));
matrix.mulPose(Axis.XN.rotationDegrees(8));
} else {
matrix.mulPose(Axis.XP.rotationDegrees(8));
}
carry.getActiveScript().ifPresent(script -> CarryRenderHelper.performScriptTransformation(matrix, script));
return matrix;
} else {
CarryRenderHelper.applyBlockTransformations(player, matrix, carry.getBlock().getBlock());
carry.getActiveScript().ifPresent(script -> CarryRenderHelper.performScriptTransformation(matrix, script));
PoseStack.Pose p = matrix.last();
PoseStack copy = new PoseStack();
copy.mulPose(p.pose());
matrix.popPose();
return copy;
}
}
public static void applyBlockTransformations(Player player, PoseStack matrix, Block block)
{
matrix.mulPose(Axis.ZN.rotationDegrees(180));
applyGeneralTransformations(player, matrix);
if (Constants.CLIENT_CONFIG.facePlayer != CarryRenderHelper.isChest(block))
{
//TODO: RealFirstPersonRender
//if ((ModList.get().isLoaded("realrender") || ModList.get().isLoaded("rfpr")) && perspective == 0)
// matrix.translate(0, 0, -0.4);
matrix.mulPose(Axis.YP.rotationDegrees(180));
}
float height = getRenderHeight(player);
float offset = (height - 1f) / 1.2f;
matrix.translate(0, -offset, 0);
}
public static void setupEntityTransformations(Player player, PoseStack matrix, CarryOnData carry, boolean firstPerson) {
Entity entity = carry.getEntity(player.level());
float height = entity.getBbHeight();
float width = entity.getBbWidth();
if(firstPerson) {
matrix.mulPose(Axis.YP.rotationDegrees(180));
matrix.scale(0.8f, 0.8f, 0.8f);
matrix.translate(0.0, -height - .2, width * 1.3 + 0.1);
carry.getActiveScript().ifPresent(script -> CarryRenderHelper.performScriptTransformation(matrix, script));
if(Constants.CLIENT_CONFIG.rotateEntitiesSideways)
matrix.mulPose(Axis.YP.rotationDegrees(90));
}
else {
applyEntityTransformations(player, matrix, entity);
carry.getActiveScript().ifPresent(script -> CarryRenderHelper.performScriptTransformation(matrix, script));
}
}
public static void applyEntityTransformations(Player player, PoseStack matrix, Entity entity)
{
Pose pose = player.getPose();
applyGeneralTransformations(player, matrix);
matrix.mulPose(Axis.XP.rotationDegrees(180));
matrix.translate(0, -3.1, -0.65);
matrix.scale(1.666f, 1.666f, 1.666f);
float height = entity.getBbHeight();
float width = entity.getBbWidth();
float multiplier = Math.min(9.9f, height * width) ;
entity.yo = 0.0f;
entity.yRotO = 0.0f;
entity.setYHeadRot(0.0f);
entity.xo = 0.0f;
entity.xRotO = 0.0f;
matrix.scale((10 - multiplier) * 0.08f, (10 - multiplier) * 0.08f, (10 - multiplier) * 0.08f);
matrix.translate(0.0, height / 2 + -(height / 4) + 1, width - 0.1 < 0.7 ? width - 0.1 + (0.7 - (width - 0.1)) : width - 0.1);
if(doSneakCheck(player))
matrix.translate(0, -0.4, 0);
if (pose == Pose.SWIMMING || pose == Pose.FALL_FLYING)
{
matrix.mulPose(Axis.XN.rotationDegrees(180));
matrix.translate(0, 0.2 * height - 2, -0.5);
}
if(Constants.CLIENT_CONFIG.rotateEntitiesSideways)
matrix.mulPose(Axis.YP.rotationDegrees(90));
}
public static void performScriptTransformation(PoseStack matrix, CarryOnScript script)
{
int perspective = getPerspective();
ScriptRender render = script.scriptRender();
Vec3 translation = render.renderTranslation().getVec();
Vec3 rotation = render.renderRotation().getVec();
Vec3 scale = render.renderscale().getVec(1, 1, 1);
Quaternionf rot = Axis.XP.rotationDegrees((float) rotation.x);
rot.mul(Axis.YP.rotationDegrees((float) rotation.y));
rot.mul(Axis.ZP.rotationDegrees((float) rotation.z));
matrix.mulPose(rot);
matrix.translate(translation.x, translation.y, perspective == 1 && script.isBlock() ? -translation.z : translation.z);
matrix.scale((float) scale.x, (float) scale.y, (float) scale.z);
}
/*
@Deprecated
public static void renderBakedModel(ItemStack stack, PoseStack matrix, MultiBufferSource buffer, int light, BakedModel model)
{
ItemStackRenderState state = new ItemStackRenderState();
try {
ItemStackRenderState.LayerRenderState layer = state.newLayer();
if(stack.hasFoil())
layer.setFoilType(ItemStackRenderState.FoilType.STANDARD);
layer.setupBlockModel(model, RenderType.translucent());
state.render(matrix, buffer, light, OverlayTexture.NO_OVERLAY);
ItemRenderer renderer = Minecraft.getInstance().getItemRenderer();
renderer.renderStatic(stack, ItemDisplayContext.NONE, light, OverlayTexture.NO_OVERLAY, matrix, buffer, null, model, 0);
renderer.render(stack, ItemDisplayContext.NONE, false, matrix, buffer, light, OverlayTexture.NO_OVERLAY, model);
}
catch (Exception e)
{
}
}
*/
public static ItemStack getRenderItemStack(Player player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
BlockState state = carry.getBlock().getBlock().defaultBlockState();
if(carry.getActiveScript().isPresent())
{
ScriptRender render = carry.getActiveScript().get().scriptRender();
if(render.renderNameBlock().isPresent())
{
state = BuiltInRegistries.BLOCK.get(render.renderNameBlock().get()).get().value().defaultBlockState();
}
}
ItemStack renderStack = ItemStack.EMPTY;
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt());
if(ov.isPresent())
{
var renderObj = ov.get().getRenderObject();
if(renderObj.right().isPresent())
state = renderObj.right().get();
else if (renderObj.left().isPresent())
renderStack = renderObj.left().get();
}
if(renderStack.isEmpty())
renderStack = new ItemStack(state.getBlock());
return renderStack;
}
public static BlockState getRenderState(Player player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
BlockState state = carry.getBlock().getBlock().defaultBlockState();
if(carry.getActiveScript().isPresent())
{
ScriptRender render = carry.getActiveScript().get().scriptRender();
if(render.renderNameBlock().isPresent())
{
state = BuiltInRegistries.BLOCK.get(render.renderNameBlock().get()).get().value().defaultBlockState();
}
}
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt());
if(ov.isPresent())
{
var renderObj = ov.get().getRenderObject();
if(renderObj.right().isPresent())
state = renderObj.right().get();
}
return state;
}
/*
@Deprecated
public static BakedModel getRenderBlock(Player player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
ItemRenderer renderer = Minecraft.getInstance().getItemRenderer();
Minecraft.getInstance().getModelManager().specialBlockModelRenderer().get().
BlockState state = getRenderState(player);
BakedModel model = Minecraft.getInstance().getBlockRenderer().getBlockModel(state);
if(state.getRenderShape() != RenderShape.MODEL || model.isCustomRenderer() || model.getQuads(state, null, RandomSource.create()).size() <= 0) {
ItemStack stack = new ItemStack(state.getBlock());
model = renderer.getModel(stack, player.level(), player, 0);
}
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt());
if(ov.isPresent())
{
var renderObj = ov.get().getRenderObject();
if(renderObj.left().isPresent())
model = renderer.getModel(renderObj.left().get(), player.level(), player, 0);
}
return model;
}
*/
public static Entity getRenderEntity(Player player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
Entity entity = carry.getEntity(player.level());
if(carry.getActiveScript().isPresent())
{
CarryOnScript script = carry.getActiveScript().get();
ScriptRender render = script.scriptRender();
if(render.renderNameEntity().isPresent())
entity = BuiltInRegistries.ENTITY_TYPE.get(render.renderNameEntity().get()).get().value().create(player.level(), EntitySpawnReason.EVENT);
if(render.renderNBT().isPresent()) {
ValueInput input = TagValueInput.create(new ProblemReporter.ScopedCollector(Constants.LOG), player.registryAccess(), render.renderNBT().get());
entity.load(input);
}
}
return entity;
}
public static float getRenderWidth(Player player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying(CarryType.BLOCK))
{
BlockState state = getRenderState(player);
VoxelShape shape = state.getShape(player.level(), player.blockPosition());
if(shape == null || shape.isEmpty())
return 1f;
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt());
if(ov.isPresent())
{
var renderObj = ov.get().getRenderObject();
if(renderObj.left().isPresent())
return 0.8f;
}
float width = (float)Math.abs(shape.bounds().maxX - shape.bounds().minX);
return width;
}
else if(carry.isCarrying(CarryType.ENTITY))
{
Entity entity = getRenderEntity(player);
float w = entity.getBbWidth();
if (Constants.CLIENT_CONFIG.rotateEntitiesSideways)
return w - (w*w) * 0.35f;
return w * 0.9f;
}
else
return 1f;
}
public static float getRenderHeight(Player player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying(CarryType.BLOCK))
{
BlockState state = getRenderState(player);
VoxelShape shape = state.getShape(player.level(), player.blockPosition());
if(shape == null || shape.isEmpty())
return 1f;
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt());
if(ov.isPresent())
{
var renderObj = ov.get().getRenderObject();
if(renderObj.left().isPresent())
return 0.5f;
}
float height = (float)Math.abs(shape.bounds().maxY - shape.bounds().minY);
return height;
}
else if(carry.isCarrying(CarryType.ENTITY))
{
Entity entity = getRenderEntity(player);
return entity.getBbHeight();
}
else
return 1f;
}
@SuppressWarnings("resource")
public static int getPerspective()
{
boolean isThirdPerson = !Minecraft.getInstance().options.getCameraType().isFirstPerson(); // isThirdPerson
boolean isThirdPersonReverse = Minecraft.getInstance().options.getCameraType().isMirrored();
if (!isThirdPerson && !isThirdPersonReverse)
return 0;
if (isThirdPerson && !isThirdPersonReverse)
return 1;
return 2;
}
public static boolean doSneakCheck(Player player)
{
if (player.getAbilities().flying)
return false;
return player.isShiftKeyDown() || player.isCrouching();
}
public static boolean isChest(Block block)
{
return block == Blocks.CHEST || block == Blocks.ENDER_CHEST || block == Blocks.TRAPPED_CHEST || block instanceof ChestBlock;
}
}

View File

@ -0,0 +1,22 @@
package tschipp.carryon.client.render;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.player.PlayerModel;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.entity.RenderLayerParent;
import net.minecraft.client.renderer.entity.layers.RenderLayer;
import net.minecraft.client.renderer.entity.state.AvatarRenderState;
public class CarryingItemRenderLayer<M extends PlayerModel> extends RenderLayer<AvatarRenderState, M> {
public CarryingItemRenderLayer(RenderLayerParent<AvatarRenderState, M> renderer) {
super(renderer);
}
@Override
public void submit(PoseStack poseStack, SubmitNodeCollector nodeCollector, int packedLight,
AvatarRenderState renderState, float yRot, float xRot) {
if (renderState instanceof ICarryOnRenderState carryOnRenderState){
CarriedObjectRender.draw(carryOnRenderState.getPlayer(), poseStack, packedLight, Minecraft.getInstance().getDeltaTracker().getGameTimeDeltaPartialTick(true), nodeCollector,false);
}
}
}

View File

@ -0,0 +1,20 @@
package tschipp.carryon.client.render;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.common.carry.CarryOnData;
public interface ICarryOnRenderState {
CarryOnData getCarryOnData();
void setCarryOnData(CarryOnData data);
float getRenderWidth();
void setRenderWidth(float val);
Player getPlayer();
void setPlayer(Player player);
}

View File

@ -0,0 +1,279 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.common.carry;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.Tag;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.entity.AreaEffectCloud;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.storage.TagValueInput;
import net.minecraft.world.level.storage.TagValueOutput;
import net.minecraft.world.level.storage.ValueInput;
import tschipp.carryon.Constants;
import tschipp.carryon.common.scripting.CarryOnScript;
import javax.annotation.Nullable;
import java.util.Optional;
import java.util.UUID;
public class CarryOnData {
private CarryType type;
private CompoundTag nbt;
private boolean keyPressed = false;
private CarryOnScript activeScript;
private int selectedSlot = 0;
private static final ProblemReporter problemReporter = new ProblemReporter.ScopedCollector(Constants.LOG);
public static final Codec<CarryOnData> CODEC = CompoundTag.CODEC.flatXmap(
tag -> {
try {
return DataResult.success(new CarryOnData(tag));
} catch (Exception e) {
return DataResult.error(e::getMessage);
}
},
carry -> {
try {
return DataResult.success(carry.getNbt());
} catch (Exception e) {
return DataResult.error(e::getMessage);
}
}
);
public static final StreamCodec<RegistryFriendlyByteBuf, CarryOnData> STREAM_CODEC = ByteBufCodecs.fromCodecWithRegistries(CODEC);
public static final String SERIALIZATION_KEY = "CarryOnData";
public CarryOnData(CompoundTag data)
{
if(data.contains("type"))
this.type = CarryType.valueOf(data.getStringOr("type", "INVALID"));
else
this.type = CarryType.INVALID;
this.nbt = data;
this.keyPressed = data.getBooleanOr("keyPressed", false);
if(data.contains("activeScript"))
{
DataResult<CarryOnScript> res = CarryOnScript.CODEC.parse(NbtOps.INSTANCE, data.get("activeScript"));
this.activeScript = res.getOrThrow((s) -> {throw new RuntimeException("Failed to decode activeScript during CarryOnData serialization: " + s);});
}
this.selectedSlot = data.getIntOr("selected", 0);
}
public CarryType getType()
{
return this.type;
}
public CompoundTag getNbt()
{
nbt.putString("type", type.toString());
nbt.putBoolean("keyPressed", keyPressed);
if(activeScript != null)
{
DataResult<Tag> res = CarryOnScript.CODEC.encodeStart(NbtOps.INSTANCE, activeScript);
Tag tag = res.getOrThrow((s) -> {throw new RuntimeException("Failed to encode activeScript during CarryOnData serialization: " + s);});
nbt.put("activeScript", tag);
}
nbt.putInt("selected", this.selectedSlot);
return nbt;
}
public CompoundTag getContentNbt()
{
if(type == CarryType.BLOCK && nbt.contains("block"))
return nbt.getCompoundOrEmpty("block");
else if(type == CarryType.ENTITY && nbt.contains("entity"))
return nbt.getCompoundOrEmpty("entity");
return null;
}
public void setBlock(BlockState state, @Nullable BlockEntity tile, ServerPlayer player, BlockPos pos)
{
this.type = CarryType.BLOCK;
if(state.hasProperty(BlockStateProperties.WATERLOGGED))
state = state.setValue(BlockStateProperties.WATERLOGGED, false);
CompoundTag stateData = NbtUtils.writeBlockState(state);
nbt.put("block", stateData);
if(tile != null)
{
TagValueOutput output = TagValueOutput.createWithContext(problemReporter, player.registryAccess());
tile.saveWithId(output);
Tag tileData = output.buildResult();
nbt.put("tile", tileData);
}
}
public BlockState getBlock()
{
if(this.type != CarryType.BLOCK)
throw new IllegalStateException("Called getBlock on data that contained " + this.type);
return NbtUtils.readBlockState(BuiltInRegistries.BLOCK, nbt.getCompoundOrEmpty("block"));
}
@Nullable
public BlockEntity getBlockEntity(BlockPos pos, HolderLookup.Provider lookup)
{
if(this.type != CarryType.BLOCK)
throw new IllegalStateException("Called getBlockEntity on data that contained " + this.type);
if(!nbt.contains("tile"))
return null;
return BlockEntity.loadStatic(pos, this.getBlock(), nbt.getCompoundOrEmpty("tile"), lookup);
}
public void setEntity(Entity entity)
{
this.type = CarryType.ENTITY;
TagValueOutput output = TagValueOutput.createWithContext(new ProblemReporter.ScopedCollector(Constants.LOG), entity.registryAccess());
entity.save(output);
Tag entityData = output.buildResult();
nbt.put("entity", entityData);
}
public Entity getEntity(Level level)
{
if(this.type != CarryType.ENTITY)
throw new IllegalStateException("Called getEntity on data that contained " + this.type);
ValueInput in = TagValueInput.create(problemReporter, level.registryAccess(), nbt.getCompoundOrEmpty("entity"));
var optionalEntity = EntityType.create(in, level, EntitySpawnReason.BUCKET);
if(optionalEntity.isPresent())
return optionalEntity.get();
Constants.LOG.error("Called EntityType#create even though no entity data was present. Data: " + nbt.toString());
this.clear();
return new AreaEffectCloud(level, 0, 0, 0);
}
public Optional<CarryOnScript> getActiveScript()
{
if(activeScript == null)
return Optional.empty();
return Optional.of(activeScript);
}
public void setActiveScript(CarryOnScript script)
{
this.activeScript = script;
}
public void setCarryingPlayer(Player player)
{
this.type = CarryType.PLAYER;
nbt.putString("player", player.getStringUUID().toString());
}
public Player getCarryingPlayer(Level level)
{
if(this.type != CarryType.PLAYER)
throw new IllegalStateException("Called getCarryingPlayer on data that contained " + this.type);
if(!nbt.contains("player"))
return null;
UUID uuid = UUID.fromString(nbt.getString("player").get());
return level.getServer().getPlayerList().getPlayer(uuid);
}
public boolean isCarrying()
{
return this.type != CarryType.INVALID;
}
public boolean isCarrying(CarryType type)
{
return this.type == type;
}
public boolean isKeyPressed() {return this.keyPressed;}
public void setKeyPressed(boolean val) {
this.keyPressed = val;
this.nbt.putBoolean("keyPressed", val);
}
public void setSelected(int selectedSlot) {
this.selectedSlot = selectedSlot;
}
public int getSelected() {
return this.selectedSlot;
}
public void clear()
{
this.type = CarryType.INVALID;
this.nbt = new CompoundTag();
this.activeScript = null;
}
public CarryOnData clone() {
return new CarryOnData(nbt.copy());
}
public int getTick()
{
return this.nbt.getIntOr("tick", -1);
}
public void setTick(int tick) {
this.nbt.putInt("tick", tick);
}
public enum CarryType {
BLOCK,
ENTITY,
PLAYER,
INVALID
}
}

View File

@ -0,0 +1,40 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.common.carry;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.platform.Services;
public class CarryOnDataManager {
public static CarryOnData getCarryData(Player player)
{
return Services.PLATFORM.getCarryData(player);
}
public static void setCarryData(Player player, CarryOnData data)
{
data.setSelected(player.getInventory().getSelectedSlot());
data.setTick(player.tickCount);
Services.PLATFORM.setCarryData(player, data);
}
}

View File

@ -0,0 +1,291 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.common.carry;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.Entity.RemovalReason;
import net.minecraft.world.entity.animal.Animal;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.DoorBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.storage.TagValueOutput;
import net.minecraft.world.phys.Vec3;
import tschipp.carryon.CarryOnCommon;
import tschipp.carryon.Constants;
import tschipp.carryon.common.config.ListHandler;
import tschipp.carryon.common.pickupcondition.PickupCondition;
import tschipp.carryon.common.pickupcondition.PickupConditionHandler;
import tschipp.carryon.common.scripting.CarryOnScript;
import tschipp.carryon.common.scripting.ScriptManager;
import tschipp.carryon.networking.clientbound.ClientboundStartRidingOtherPlayerPacket;
import tschipp.carryon.platform.Services;
import javax.annotation.Nullable;
import java.util.Optional;
import java.util.UUID;
import java.util.function.BiFunction;
import java.util.function.Function;
public class PickupHandler {
public static boolean canCarryGeneral(ServerPlayer player, Vec3 pos)
{
if(!player.getMainHandItem().isEmpty() || !player.getOffhandItem().isEmpty())
return false;
if(player.position().distanceTo(pos) > Constants.COMMON_CONFIG.settings.maxDistance)
return false;
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying())
return false;
if(!carry.isKeyPressed())
return false;
//Needed so that we don't pick up and place in the same tick
if(player.tickCount == carry.getTick())
return false;
if (player.gameMode.getGameModeForPlayer() == GameType.SPECTATOR || player.gameMode.getGameModeForPlayer() == GameType.ADVENTURE)
return false;
return true;
}
public static boolean tryPickUpBlock(ServerPlayer player, BlockPos pos, Level level, @Nullable BiFunction<BlockState, BlockPos, Boolean> pickupCallback)
{
if(!canCarryGeneral(player, Vec3.atCenterOf(pos)))
return false;
CarryOnData carry = CarryOnDataManager.getCarryData(player);
BlockEntity blockEntity = level.getBlockEntity(pos);
BlockState state = level.getBlockState(pos);
CompoundTag nbt = null;
if(blockEntity != null) {
TagValueOutput output = TagValueOutput.createWithContext(new ProblemReporter.ScopedCollector(Constants.LOG), level.registryAccess());
blockEntity.saveWithId(output);
nbt = output.buildResult();
}
Optional<CarryOnScript> result = ScriptManager.inspectBlock(state, level, pos, nbt);
boolean overrideChecks = result.map(CarryOnScript::overrideChecks).orElse(false);
if(!ListHandler.isPermitted(state.getBlock()))
return false;
// Reject pickup of Double blocks, if they use the vanilla property
if(hasPropertyType(state, DoorBlock.HALF))
return false;
if(!overrideChecks && (state.getDestroySpeed(level, pos) == -1 && !player.isCreative() && !Constants.COMMON_CONFIG.settings.pickupUnbreakableBlocks))
return false;
if(!overrideChecks && (blockEntity == null && !Constants.COMMON_CONFIG.settings.pickupAllBlocks))
return false;
//Check if TE is locked
if(blockEntity != null)
{
if(nbt.contains("Lock") && !nbt.getString("Lock").equals(""))
return false;
}
Optional<PickupCondition> cond = PickupConditionHandler.getPickupCondition(state);
if(cond.isPresent())
{
if(!cond.get().isFulfilled(player))
return false;
}
boolean doPickup = pickupCallback == null ? true : pickupCallback.apply(state, pos);
if(!doPickup)
return false;
if(result.isPresent())
{
CarryOnScript script = result.get();
if(!script.fulfillsConditions(player))
return false;
carry.setActiveScript(script);
String cmd = script.scriptEffects().commandInit();
if(!cmd.isEmpty())
player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
}
carry.setBlock(state, blockEntity, player, pos);
level.removeBlockEntity(pos);
level.removeBlock(pos, false);
CarryOnDataManager.setCarryData(player, carry);
level.playSound(null, pos, state.getSoundType().getHitSound(), SoundSource.BLOCKS, 1.0f, 0.5f);
player.swing(InteractionHand.MAIN_HAND, true);
if (!player.isCreative() || Constants.COMMON_CONFIG.settings.slownessInCreative)
player.addEffect(new MobEffectInstance(MobEffects.SLOWNESS, 100000000, CarryOnCommon.potionLevel(carry, player.level()), false, false));
return true;
}
public static boolean tryPickupEntity(ServerPlayer player, Entity entity, @Nullable Function<Entity, Boolean> pickupCallback)
{
if(!canCarryGeneral(player, entity.position()))
return false;
if (entity.invulnerableTime != 0)
return false;
if(entity.isRemoved())
return false;
if (entity instanceof TamableAnimal tame)
{
EntityReference<LivingEntity> ref = tame.getOwnerReference();
if (ref != null) {
UUID owner = ref.getUUID();
UUID playerID = player.getGameProfile().id();
if (!owner.equals(playerID))
return false;
}
}
Optional<CarryOnScript> result = ScriptManager.inspectEntity(entity);
boolean overrideChecks = result.map(CarryOnScript::overrideChecks).orElse(false);
if(!ListHandler.isPermitted(entity))
{
//We can pick up baby animals even if the grown up animal is blacklisted.
if(!overrideChecks && (!(entity instanceof AgeableMob ageableMob && Constants.COMMON_CONFIG.settings.allowBabies && (ageableMob.getAge() < 0 || ageableMob.isBaby()))))
return false;
}
//Non-Creative only guards
if(!player.isCreative())
{
if(!overrideChecks && (!Constants.COMMON_CONFIG.settings.pickupHostileMobs && entity.getType().getCategory() == MobCategory.MONSTER))
return false;
if(Constants.COMMON_CONFIG.settings.maxEntityHeight < entity.getBbHeight() || Constants.COMMON_CONFIG.settings.maxEntityWidth < entity.getBbWidth())
return false;
}
Optional<PickupCondition> cond = PickupConditionHandler.getPickupCondition(entity);
if(cond.isPresent())
{
if(!cond.get().isFulfilled(player))
return false;
}
boolean doPickup = pickupCallback == null || pickupCallback.apply(entity);
if(!doPickup)
return false;
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(result.isPresent())
{
CarryOnScript script = result.get();
if(!script.fulfillsConditions(player))
return false;
carry.setActiveScript(script);
}
if (entity instanceof Player otherPlayer) {
if (!Constants.COMMON_CONFIG.settings.pickupPlayers)
return false;
if (!player.isCreative() && otherPlayer.isCreative())
return false;
otherPlayer.ejectPassengers();
otherPlayer.stopRiding();
if (result.isPresent()) {
String cmd = result.get().scriptEffects().commandInit();
if (!cmd.isEmpty())
player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
}
otherPlayer.startRiding(player, true, false);
Services.PLATFORM.sendPacketToAllPlayers(Constants.PACKET_ID_START_RIDING_OTHER, new ClientboundStartRidingOtherPlayerPacket(player.getId(), otherPlayer.getId(), true), player.level());
carry.setCarryingPlayer(otherPlayer);
player.swing(InteractionHand.MAIN_HAND, true);
player.level().playSound(null, player.getOnPos(), SoundEvents.ARMOR_EQUIP_GENERIC.value(), SoundSource.AMBIENT, 1.0f, 0.5f);
CarryOnDataManager.setCarryData(player, carry);
if (!player.isCreative() || Constants.COMMON_CONFIG.settings.slownessInCreative)
player.addEffect(new MobEffectInstance(MobEffects.SLOWNESS, 100000000, CarryOnCommon.potionLevel(carry, player.level()), false, false));
return true;
}
entity.ejectPassengers();
entity.stopRiding();
if (entity instanceof Animal animal) {
animal.dropLeash();
}
if(result.isPresent())
{
String cmd = result.get().scriptEffects().commandInit();
if(!cmd.isEmpty())
player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
}
carry.setEntity(entity);
entity.remove(RemovalReason.UNLOADED_WITH_PLAYER);
player.level().playSound(null, player.getOnPos(), SoundEvents.ARMOR_EQUIP_GENERIC.value(), SoundSource.AMBIENT, 1.0f, 0.5f);
CarryOnDataManager.setCarryData(player, carry);
player.swing(InteractionHand.MAIN_HAND, true);
if (!player.isCreative() || Constants.COMMON_CONFIG.settings.slownessInCreative)
player.addEffect(new MobEffectInstance(MobEffects.SLOWNESS, 100000000, CarryOnCommon.potionLevel(carry, player.level()), false, false));
return true;
}
private static <T extends Comparable<T>> boolean hasPropertyType(BlockState state, Property<T> prop) {
for (var p : state.getProperties()) {
if(p.getValueClass().equals(prop.getValueClass()))
return true;
}
return false;
}
}

View File

@ -0,0 +1,388 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.common.carry;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.animal.equine.Horse;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.gamerules.GameRules;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
import tschipp.carryon.Constants;
import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.config.ListHandler;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptEffects;
import tschipp.carryon.networking.clientbound.ClientboundStartRidingOtherPlayerPacket;
import tschipp.carryon.platform.Services;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.BiFunction;
public class PlacementHandler
{
public static boolean tryPlaceBlock(ServerPlayer player, BlockPos pos, Direction facing, @Nullable BiFunction<BlockPos, BlockState, Boolean> placementCallback)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (!carry.isCarrying(CarryOnData.CarryType.BLOCK))
return false;
if (player.tickCount == carry.getTick())
return false;
Level level = player.level();
BlockState state = carry.getBlock();
BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos));
if (!level.getBlockState(pos).canBeReplaced(context))
pos = pos.relative(facing);
context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos));
BlockEntity blockEntity = carry.getBlockEntity(pos, level.registryAccess());
state = getPlacementState(state, player, context, pos);
boolean canPlace = state.canSurvive(level, pos) && level.mayInteract(player, pos) && level.getBlockState(pos).canBeReplaced(context) && level.isUnobstructed(state, pos, CollisionContext.of(player));
if (!canPlace) {
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.LAVA_POP, SoundSource.PLAYERS, 0.5F, 0.5F);
return false;
}
boolean doPlace = placementCallback == null || placementCallback.apply(pos, state);
if (!doPlace)
return false;
if(level.isOutsideBuildHeight(pos))
return false;
if (carry.getActiveScript().isPresent()) {
ScriptEffects effects = carry.getActiveScript().get().scriptEffects();
String cmd = effects.commandPlace();
if (!cmd.isEmpty())
player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
}
level.setBlockAndUpdate(pos, state);
if (blockEntity != null) {
blockEntity.setBlockState(state);
level.setBlockEntity(blockEntity);
}
level.updateNeighborsAt(pos.relative(Direction.DOWN), level.getBlockState(pos.relative(Direction.DOWN)).getBlock());
carry.clear();
CarryOnDataManager.setCarryData(player, carry);
player.playSound(state.getSoundType().getPlaceSound(), 1.0f, 0.5f);
level.playSound(null, pos, state.getSoundType().getPlaceSound(), SoundSource.BLOCKS, 1.0f, 0.5f);
player.swing(InteractionHand.MAIN_HAND, true);
player.removeEffect(MobEffects.SLOWNESS);
return true;
}
private static BlockState getPlacementState(BlockState state, ServerPlayer player, BlockPlaceContext context, BlockPos pos)
{
BlockState placementState = state.getBlock().getStateForPlacement(context);
if (placementState == null || placementState.getBlock() != state.getBlock())
placementState = state;
for (var prop : placementState.getProperties()) {
if (prop.getValueClass() == Direction.class)
state = updateProperty(state, placementState, prop);
if (prop.getValueClass() == Direction.Axis.class)
state = updateProperty(state, placementState, prop);
//This is needed for certain blocks, otherwise we get problems like chests not connecting
if (ListHandler.isPropertyException(prop)) {
state = updateProperty(state, placementState, prop);
}
}
BlockState updatedState = Block.updateFromNeighbourShapes(state, player.level(), pos);
if (updatedState.getBlock() == state.getBlock())
state = updatedState;
if (placementState.hasProperty(BlockStateProperties.WATERLOGGED) && state.hasProperty(BlockStateProperties.WATERLOGGED))
state = state.setValue(BlockStateProperties.WATERLOGGED, placementState.getValue(BlockStateProperties.WATERLOGGED));
return state;
}
private static <T extends Comparable<T>> BlockState updateProperty(BlockState state, BlockState otherState, Property<T> prop)
{
var val = otherState.getValue(prop);
return state.setValue(prop, val);
}
public static boolean tryPlaceEntity(ServerPlayer player, BlockPos pos, Direction facing, @Nullable BiFunction<Vec3, Entity, Boolean> placementCallback)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (!carry.isCarrying(CarryType.ENTITY) && !carry.isCarrying(CarryType.PLAYER))
return false;
if (player.tickCount == carry.getTick())
return false;
Level level = player.level();
BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos));
if (!level.getBlockState(pos).canBeReplaced(context)) {
pos = pos.relative(facing);
context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos));
}
if (!level.getBlockState(pos).canBeReplaced(context)) {
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.LAVA_POP, SoundSource.PLAYERS, 0.5F, 0.5F);
return false;
}
Vec3 placementPos = Vec3.atBottomCenterOf(pos);
if (carry.isCarrying(CarryType.PLAYER)) {
Entity otherPlayer = carry.getCarryingPlayer(level);
player.ejectPassengers();
Services.PLATFORM.sendPacketToAllPlayers(Constants.PACKET_ID_START_RIDING_OTHER, new ClientboundStartRidingOtherPlayerPacket(player.getId(), otherPlayer.getId(), false), player.level());
carry.clear();
CarryOnDataManager.setCarryData(player, carry);
otherPlayer.teleportTo(placementPos.x, placementPos.y, placementPos.z);
player.swing(InteractionHand.MAIN_HAND, true);
player.removeEffect(MobEffects.SLOWNESS);
return true;
}
Entity entity = carry.getEntity(level);
entity.setPos(placementPos);
boolean doPlace = placementCallback == null || placementCallback.apply(placementPos, entity);
if (!doPlace)
return false;
if (carry.getActiveScript().isPresent()) {
ScriptEffects effects = carry.getActiveScript().get().scriptEffects();
String cmd = effects.commandPlace();
if (!cmd.isEmpty())
player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
}
level.addFreshEntity(entity);
if (entity instanceof Mob mob)
mob.playAmbientSound();
player.swing(InteractionHand.MAIN_HAND, true);
carry.clear();
CarryOnDataManager.setCarryData(player, carry);
player.removeEffect(MobEffects.SLOWNESS);
return true;
}
public static void tryStackEntity(ServerPlayer player, Entity entityClicked)
{
if(!Constants.COMMON_CONFIG.settings.stackableEntities)
return;
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (!carry.isCarrying(CarryType.ENTITY) && !carry.isCarrying(CarryType.PLAYER))
return;
Level level = player.level();
Entity entityHeld;
if (carry.isCarrying(CarryType.ENTITY))
entityHeld = carry.getEntity(level);
else
entityHeld = player.getFirstPassenger();
if(entityHeld == null)
return;
double sizeHeldEntity = entityHeld.getBbHeight() * entityHeld.getBbWidth();
double distance = entityClicked.blockPosition().distSqr(player.blockPosition());
Entity lowestEntity = entityClicked.getRootVehicle();
int numPassengers = getPassengerCount(lowestEntity);
if (numPassengers < Constants.COMMON_CONFIG.settings.maxEntityStackLimit - 1) {
Entity topEntity = getTopPassenger(lowestEntity);
if (topEntity == entityHeld)
return;
if (ListHandler.isStackingPermitted(topEntity)) {
double sizeEntity = topEntity.getBbHeight() * topEntity.getBbWidth();
if (!Constants.COMMON_CONFIG.settings.entitySizeMattersStacking || sizeHeldEntity <= sizeEntity) {
if (topEntity instanceof Horse horse)
horse.setTamed(true);
if (distance < 6) {
double tempX = entityClicked.getX();
double tempY = entityClicked.getY();
double tempZ = entityClicked.getZ();
if (carry.isCarrying(CarryType.ENTITY)) {
entityHeld.setPos(tempX, tempY + 2.6, tempZ);
level.addFreshEntity(entityHeld);
entityHeld.teleportTo(tempX, tempY, tempZ);
}
entityHeld.startRiding(topEntity, false,false);
} else {
if (carry.isCarrying(CarryType.ENTITY)) {
entityHeld.setPos(entityClicked.getX(), entityClicked.getY(), entityClicked.getZ());
level.addFreshEntity(entityHeld);
}
entityHeld.startRiding(topEntity, false,false);
}
if (carry.getActiveScript().isPresent()) {
ScriptEffects effects = carry.getActiveScript().get().scriptEffects();
String cmd = effects.commandPlace();
if (!cmd.isEmpty())
player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
}
player.swing(InteractionHand.MAIN_HAND, true);
carry.clear();
CarryOnDataManager.setCarryData(player, carry);
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.HORSE_SADDLE, SoundSource.PLAYERS, 0.5F, 1.5F);
player.removeEffect(MobEffects.SLOWNESS);
} else {
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.LAVA_POP, SoundSource.PLAYERS, 0.5F, 0.5F);
}
}
} else {
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.LAVA_POP, SoundSource.PLAYERS, 0.5F, 0.5F);
}
}
public static void placeCarriedOnDeath(ServerPlayer oldPlayer, ServerPlayer newPlayer, boolean died)
{
CarryOnData carry = CarryOnDataManager.getCarryData(oldPlayer);
if (oldPlayer.level().getGameRules().get(GameRules.KEEP_INVENTORY) || !died) {
if (!carry.isCarrying(CarryType.PLAYER)) {
CarryOnDataManager.setCarryData(newPlayer, carry);
newPlayer.getInventory().setSelectedSlot(oldPlayer.getInventory().getSelectedSlot());
return;
}
}
placeCarried(oldPlayer);
}
public static void placeCarried(ServerPlayer player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (carry.isCarrying(CarryType.ENTITY)) {
Entity entity = carry.getEntity(player.level());
entity.setPos(player.position());
player.level().addFreshEntity(entity);
} else if (carry.isCarrying(CarryType.BLOCK)) {
BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(Vec3.atCenterOf(player.blockPosition()), Direction.DOWN, player.blockPosition()));
BlockState state = getPlacementState(carry.getBlock(), player, context, player.blockPosition());
BlockPos pos = getDeathPlacementPos(state, player);
BlockEntity blockEntity = carry.getBlockEntity(pos, player.level().registryAccess());
player.level().setBlock(pos, state, 3);
if (blockEntity != null)
player.level().setBlockEntity(blockEntity);
} else if (carry.isCarrying(CarryType.PLAYER)) {
player.ejectPassengers();
}
carry.clear();
CarryOnDataManager.setCarryData(player, carry);
player.removeEffect(MobEffects.SLOWNESS);
}
private static BlockPos getDeathPlacementPos(BlockState state, ServerPlayer player)
{
BlockPos p = player.blockPosition();
int DISTANCE = 15;
List<BlockPos> potentialPositions = new ArrayList<>();
for (int j = 0; j < DISTANCE * 2; j++) {
for (int i = 0; i < DISTANCE * 2; i++) {
for (int k = 0; k < DISTANCE * 2; k++) {
int x = i % 2 == 0 ? i / 2 : -(i / 2);
int y = j % 2 == 0 ? j / 2 : -(j / 2);
int z = k % 2 == 0 ? k / 2 : -(k / 2);
potentialPositions.add(new BlockPos(p.getX() + x, p.getY() + y, p.getZ() + z));
}
}
}
potentialPositions.sort(Comparator.comparingDouble(posA -> player.distanceToSqr(posA.getCenter())));
for(BlockPos potential : potentialPositions)
{
BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(Vec3.atCenterOf(potential), Direction.DOWN, potential));
boolean canPlace = state.canSurvive(player.level(), potential) && player.level().getBlockState(potential).canBeReplaced(context) && player.level().isUnobstructed(state, potential, CollisionContext.of(player));
if (canPlace)
return potential;
}
return p;
}
private static int getPassengerCount(Entity entity)
{
int passengers = 0;
while (entity.isVehicle()) {
List<Entity> pass = entity.getPassengers();
if (!pass.isEmpty()) {
entity = pass.get(0);
passengers++;
}
}
return passengers;
}
private static Entity getTopPassenger(Entity entity)
{
Entity top = entity;
while (entity.isVehicle()) {
List<Entity> pass = entity.getPassengers();
if (!pass.isEmpty()) {
entity = pass.get(0);
top = entity;
}
}
return top;
}
}

View File

@ -0,0 +1,25 @@
package tschipp.carryon.common.carry.compat;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import javax.annotation.Nullable;
public class CarryOnModHooks {
public record CanPickupBlockHook(ServerPlayer player, BlockPos pos, BlockState state) {
}
public record CanPickupEntityHook(ServerPlayer player, Entity entity) {
}
public record SaveBlockHook(ServerPlayer player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity) {
}
}

View File

@ -0,0 +1,173 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.common.command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.permissions.Permission;
import net.minecraft.server.permissions.PermissionLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.state.BlockState;
import tschipp.carryon.Constants;
import tschipp.carryon.client.modeloverride.ModelOverride;
import tschipp.carryon.client.modeloverride.ModelOverrideHandler;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.common.carry.PlacementHandler;
import tschipp.carryon.common.pickupcondition.PickupCondition;
import tschipp.carryon.common.pickupcondition.PickupConditionHandler;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
public class CommandCarryOn
{
public static void register(CommandDispatcher<CommandSourceStack> dispatcher)
{
LiteralArgumentBuilder<CommandSourceStack> builder = Commands.literal("carryon")
.then(Commands.literal("debug").executes(cmd -> handleDebug(cmd.getSource())))
.then(Commands.literal("clear").executes(cmd -> handleClear(cmd.getSource(), Collections.singleton(cmd.getSource().getPlayerOrException()))))
.then(Commands.literal("clear").then(Commands.argument("target", EntityArgument.players()).requires(src -> src.permissions().hasPermission(new Permission.HasCommandLevel(PermissionLevel.GAMEMASTERS))).executes(cmd -> handleClear(cmd.getSource(), EntityArgument.getPlayers(cmd, "target")))))
.then(Commands.literal("place").requires(src -> src.permissions().hasPermission(new Permission.HasCommandLevel(PermissionLevel.GAMEMASTERS))).executes(cmd -> handlePlace(cmd.getSource(), Collections.singleton(cmd.getSource().getPlayerOrException()))))
.then(Commands.literal("place").then(Commands.argument("target", EntityArgument.players()).requires(src -> src.permissions().hasPermission(new Permission.HasCommandLevel(PermissionLevel.GAMEMASTERS))).executes(cmd -> handlePlace(cmd.getSource(), EntityArgument.getPlayers(cmd, "target")))))
;
dispatcher.register(builder);
}
private static int handleDebug(CommandSourceStack source)
{
try
{
if (source.getEntityOrException() != null)
{
ServerPlayer player = source.getPlayerOrException();
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (carry.isCarrying(CarryType.BLOCK))
{
BlockState block = carry.getBlock();
log(source,"Block: " + block.getBlock());
log(source,"BlockState: " + block);
log(source,"NBT: " + carry.getNbt());
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(block, carry.getContentNbt());
if(ov.isPresent())
log(source, "Override Model: " + ov.get().getRenderObject());
Optional<PickupCondition> cond = PickupConditionHandler.getPickupCondition(block);
if(cond.isPresent())
log(source, "Custom Pickup Condition: " + cond.get().getCondition());
return 1;
}
else if (carry.isCarrying(CarryType.ENTITY))
{
Entity entity = carry.getEntity(player.level());
log(source,"Entity: " + entity);
log(source,"Entity Name: " + entity.getType());
log(source,"NBT: " + carry.getNbt());
Optional<PickupCondition> cond = PickupConditionHandler.getPickupCondition(entity);
if(cond.isPresent())
log(source, "Custom Pickup Condition: " + cond.get().getCondition());
return 1;
}
else if(carry.isCarrying(CarryType.PLAYER))
{
log(source, "Carrying Player.");
}
}
}
catch (CommandSyntaxException e)
{
}
return 0;
}
private static int handleClear(CommandSourceStack source, Collection<ServerPlayer> players)
{
int cleared = 0;
for (ServerPlayer player : players)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
carry.clear();
CarryOnDataManager.setCarryData(player, carry);
cleared++;
}
int finalCleared = cleared;
if (cleared != 1) {
source.sendSuccess(() -> Component.literal("Cleared " + finalCleared + " Items!"), true);
}
else {
source.sendSuccess(() -> Component.literal("Cleared " + finalCleared + " Item!"), true);
}
return 1;
}
private static int handlePlace(CommandSourceStack source, Collection<ServerPlayer> players)
{
int cleared = 0;
for (ServerPlayer player : players)
{
PlacementHandler.placeCarried(player);
cleared++;
}
int finalCleared = cleared;
if (cleared != 1) {
source.sendSuccess(() -> Component.literal("Placed " + finalCleared + " Items!"), true);
}
else
source.sendSuccess(() -> Component.literal("Placed " + finalCleared + " Item!"), true);
return 1;
}
private static void log(CommandSourceStack source, String toLog)
{
source.sendSuccess(() -> Component.literal(toLog), true);
Constants.LOG.info(toLog);
}
}

View File

@ -0,0 +1,379 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.common.config;
import tschipp.carryon.config.PropertyType;
import tschipp.carryon.config.annotations.Category;
import tschipp.carryon.config.annotations.Config;
import tschipp.carryon.config.annotations.Property;
public class CarryConfig
{
@Config("carryon-common")
public static class Common
{
//Settings
@Property(
type = PropertyType.CATEGORY,
description = "General Settings"
)
public Settings settings = new Settings();
@Category(value="settings", translation = "carryon.category.settings")
public static class Settings
{
@Property(
type = PropertyType.DOUBLE,
description = "Maximum distance from where Blocks and Entities can be picked up",
minD = 0
)
public double maxDistance = 2.5;
@Property(
type = PropertyType.DOUBLE,
description = "Max width of entities that can be picked up in survival mode",
minD = 0,
maxD = 10
)
public double maxEntityWidth = 1.5;
@Property(
type = PropertyType.DOUBLE,
description = "Max height of entities that can be picked up in survival mode",
minD = 0,
maxD = 10
)
public double maxEntityHeight = 2.5;
@Property(
type = PropertyType.DOUBLE,
description = "Slowness multiplier for blocks",
minD = 0
)
public double blockSlownessMultiplier = 1;
@Property(
type = PropertyType.DOUBLE,
description = "Slowness multiplier for entities",
minD = 0
)
public double entitySlownessMultiplier = 1;
@Property(
type = PropertyType.INT,
description = "Maximum stack limit for entities",
min = 1
)
public int maxEntityStackLimit = 10;
@Property(
type = PropertyType.BOOLEAN,
description = "More complex Tile Entities slow down the player more"
)
public boolean heavyTiles = true;
@Property(
type = PropertyType.BOOLEAN,
description = "Allow all blocks to be picked up, not just Tile Entites. White/Blacklist will still be respected."
)
public boolean pickupAllBlocks = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Whether Blocks and Entities slow the creative player down when carried"
)
public boolean slownessInCreative = true;
@Property(
type = PropertyType.BOOLEAN,
description = "Whether hostile mobs should be able to picked up in survival mode"
)
public boolean pickupHostileMobs = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Larger Entities slow down the player more"
)
public boolean heavyEntities = true;
@Property(
type = PropertyType.BOOLEAN,
description = "Allow babies to be carried even when adult mob is blacklisted (or not whitelisted)"
)
public boolean allowBabies = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Use Whitelist instead of Blacklist for Blocks"
)
public boolean useWhitelistBlocks = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Use Whitelist instead of Blacklist for Entities"
)
public boolean useWhitelistEntities = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Use Whitelist instead of Blacklist for Stacking"
)
public boolean useWhitelistStacking = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Whether the player can hit blocks and entities while carrying or not"
)
public boolean hitWhileCarrying = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Whether the player drops the carried object when hit or not"
)
public boolean dropCarriedWhenHit = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Use custom Pickup Scripts. Having this set to false, will not allow you to run scripts, but will increase your performance"
)
public boolean useScripts = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Allows entities to be stacked on top of each other"
)
public boolean stackableEntities = true;
@Property(
type = PropertyType.BOOLEAN,
description = "Whether entities' size matters when stacking or not. This means that larger entities cannot be stacked on smaller ones"
)
public boolean entitySizeMattersStacking = true;
@Property(
type = PropertyType.STRING_ARRAY,
description = "Usually all the block state information is retained when placing a block that was picked up. But some information is changed to a modified property, like rotation or orientation. In this list, add additional properties that should NOT be saved and instead be updated when placed. Format: modid:block[propertyname]. Note: You don't need to add an entry for every subtype of a same block. For example, we only add an entry for one type of slab, but the change is applied to all slabs.",
validationRegex = "([a-zA-Z0-9_]+:[a-zA-Z0-9_]+)\\[([a-zA-Z0-9_,]+)\\]"
)
public String[] placementStateExceptions = {
"minecraft:chest[type]",
"minecraft:stone_button[face]",
"minecraft:vine[north,east,south,west,up]",
"minecraft:creeper_head[rotation]",
"minecraft:glow_lichen[north,east,south,west,up,down]",
"minecraft:oak_sign[rotation]",
"minecraft:oak_trapdoor[half]",
};
@Property(
type = PropertyType.BOOLEAN,
description = "Whether Players can be picked up. Creative players can't be picked up in Survival Mode"
)
public boolean pickupPlayers = true;
@Property(
type = PropertyType.BOOLEAN,
description = "Whether players in Survival Mode can pick up unbreakable blocks. Creative players always can."
)
public boolean pickupUnbreakableBlocks = false;
}
@Property(
type = PropertyType.CATEGORY,
description = "Whitelist. Read about the format here: https://github.com/Tschipp/CarryOn/wiki/Black---and-Whitelist-Config"
)
//Whitelist
public Whitelist whitelist = new Whitelist();
@Category(value="whitelist", translation = "carryon.category.whitelist")
public static class Whitelist
{
@Property(
type = PropertyType.STRING_ARRAY,
description = "Entities that CAN be picked up (useWhitelistEntities must be true)",
validationRegex = "(#?[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]*(?:\\*|[a-zA-Z0-9_]*)(?:\\*|[a-zA-Z0-9_]*)?)"
)
public String[] allowedEntities = {};
@Property(
type = PropertyType.STRING_ARRAY,
description = "Blocks that CAN be picked up (useWhitelistBlocks must be true)",
validationRegex = "(#?[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]*(?:\\*|[a-zA-Z0-9_]*)(?:\\*|[a-zA-Z0-9_]*)?)"
)
public String[] allowedBlocks = {};
@Property(
type = PropertyType.STRING_ARRAY,
description = "Entities that CAN have other entities stacked on top of them (useWhitelistStacking must be true)",
validationRegex = "(#?[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]*(?:\\*|[a-zA-Z0-9_]*)(?:\\*|[a-zA-Z0-9_]*)?)"
)
public String[] allowedStacking = {};
}
//Blacklist
@Property(
type = PropertyType.CATEGORY,
description = "Blacklist. Read about the format here: https://github.com/Tschipp/CarryOn/wiki/Black---and-Whitelist-Config"
)
public Blacklist blacklist = new Blacklist();
@Category(value="blacklist", translation = "carryon.category.blacklist")
public static class Blacklist
{
@Property(
type = PropertyType.STRING_ARRAY,
description = "Blocks that cannot be picked up",
validationRegex = "(#?[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]*(?:\\*|[a-zA-Z0-9_]*)(?:\\*|[a-zA-Z0-9_]*)?)"
)
public String[] forbiddenTiles = {
"#forge:immovable", "#forge:relocation_not_supported", "#neoforge:immovable", "#neoforge:relocation_not_supported", "minecraft:end_portal", "minecraft:piston_head",
"#c:relocation_not_supported",
"minecraft:end_gateway", "minecraft:tall_grass", "minecraft:large_fern", "minecraft:peony",
"minecraft:rose_bush", "minecraft:lilac", "minecraft:sunflower", "minecraft:*_bed",
"minecraft:*_door", "minecraft:big_dripleaf_stem", "minecraft:waterlily", "minecraft:cake",
"minecraft:nether_portal", "minecraft:tall_seagrass", "animania:block_trough",
"animania:block_invisiblock", "colossalchests:*", "ic2:*", "bigreactors:*", "forestry:*",
"tconstruct:*", "rustic:*", "botania:*", "astralsorcery:*", "quark:colored_bed_*",
"immersiveengineering:*", "embers:block_furnace", "embers:ember_bore",
"embers:ember_activator", "embers:mixer", "embers:heat_coil", "embers:large_tank",
"embers:crystal_cell", "embers:alchemy_pedestal", "embers:boiler", "embers:combustor",
"embers:catalzyer", "embers:field_chart", "embers:inferno_forge",
"storagedrawers:framingtable", "skyresources:*", "lootbags:*", "exsartagine:*",
"aquamunda:tank", "opencomputers:*", "malisisdoors:*", "industrialforegoing:*",
"minecolonies:*", "thaumcraft:pillar*", "thaumcraft:infernal_furnace",
"thaumcraft:placeholder*", "thaumcraft:infusion_matrix", "thaumcraft:golem_builder",
"thaumcraft:thaumatorium*", "magneticraft:oil_heater", "magneticraft:solar_panel",
"magneticraft:steam_engine", "magneticraft:shelving_unit", "magneticraft:grinder",
"magneticraft:sieve", "magneticraft:solar_tower", "magneticraft:solar_mirror",
"magneticraft:container", "magneticraft:pumpjack", "magneticraft:solar_panel",
"magneticraft:refinery", "magneticraft:oil_heater", "magneticraft:hydraulic_press",
"magneticraft:multiblock_gap", "refinedstorage:*", "mcmultipart:*", "enderstorage:*",
"betterstorage:*", "practicallogistics2:*", "wearablebackpacks:*", "rftools:screen",
"rftools:creative_screen", "create:*", "magic_doorknob:*", "iceandfire:*", "ftbquests:*",
"waystones:*", "contact:*", "framedblocks:*", "securitycraft:*", "forgemultipartcbe:*", "integrateddynamics:cable",
"mekanismgenerators:wind_generator", "cookingforblockheads:cabinet", "cookingforblockheads:corner", "cookingforblockheads:counter",
"cookingforblockheads:oven", "cookingforblockheads:toaster", "cookingforblockheads:milk_jar", "cookingforblockheads:cow_jar",
"cookingforblockheads:fruit_basket", "cookingforblockheads:cooking_table", "cookingforblockheads:fridge", "cookingforblockheads:sink",
"chipped:*", "irons_spellbooks:*", "create*:*", "simple_pipes:*", "libmultipart:*", "quark:tiny_potato", "ait:*",
"vampirism:*", "extrastorage:*", "relics:researching_table", "sophisticatedstorage:*chest",
"powah:*", "advancementtrophies:trophy", "mekanismgenerators:heat_generator", "mna:filler_block", "create_enchantment_industry:*", "graveyard:*", "immersivepetroleum:*",
"tardis:interior_door", "cuffed:*", "littletiles:*",
"butchersdelight:*", "irons_spellbooks:*", "extended_drawers:*", "functionalstorage:*", "sophisticatedstorage:*", "farmersdelight:*",
"modern_industrialization:*_cable",
"modern_industrialization:item_pipe",
"modern_industrialization:*_item_pipe",
"modern_industrialization:fluid_pipe",
"modern_industrialization:*_fluid_pipe",
"yigd:*", "domum_ornamentum:*", "connectiblechains:*",
"cobblemon:*", "snowrealmagic:*", "forbidden_arcanus:black_hole", "domum_ornamentum:*", "sgjourney:*", "copycats:*", "expandedstorage:*", "replication:*"
};
@Property(
type = PropertyType.STRING_ARRAY,
description = "Entities that cannot be picked up",
validationRegex = "(#?[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]*(?:\\*|[a-zA-Z0-9_]*)(?:\\*|[a-zA-Z0-9_]*)?)"
)
public String[] forbiddenEntities = {
"#c:capturing_not_supported", "#c:teleporting_not_supported",
"minecraft:end_crystal", "minecraft:ender_dragon", "minecraft:ghast", "minecraft:fireball", "minecraft:small_fireball", "minecraft:whither_skull",
"minecraft:shulker", "minecraft:leash_knot", "minecraft:armor_stand", "minecraft:whither_skull_dangerous", "minecraft:dragon_fireball",
"minecraft:item_frame", "minecraft:painting", "minecraft:shulker_bullet", "minecraft:evoker_fangs", "minecraft:glow_item_frame", "minecraft:tnt", "minecraft:trident", "minecraft:arrow", "minecraft:spectral_arrow",
"minecraft:interaction", "minecraft:marker", "minecraft:block_display", "minecraft:item_display", "minecraft:text_display",
"animania:hamster", "animania:ferret*", "animania:hedgehog*", "animania:cart",
"animania:wagon", "mynko:*", "pixelmon:*", "mocreatures:*", "quark:totem", "vehicle:*",
"securitycraft:*", "taterzens:npc", "easy_npc:*", "bodiesbodies:dead_body", "littletiles:*",
"connectiblechains:*", "cobblemon:*", "create:*", "swem:*", "toms_mobs:*"
};
@Property(
type = PropertyType.STRING_ARRAY,
description = "Entities that cannot have other entities stacked on top of them",
validationRegex = "(#?[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]*(?:\\*|[a-zA-Z0-9_]*)(?:\\*|[a-zA-Z0-9_]*)?)"
)
public String[] forbiddenStacking = {
"minecraft:horse",
"minecraft:ender_dragon"
};
}
//Custom Pickup Conditions
@Property(
type = PropertyType.CATEGORY,
description = "Custom Pickup Conditions. Read about the format here: https://github.com/Tschipp/CarryOn/wiki/Custom-Pickup-Condition-Config"
)
public CustomPickupConditions customPickupConditions = new CustomPickupConditions();
@Category(value="customPickupConditions", translation = "carryon.category.custompickupconditions")
public static class CustomPickupConditions
{
@Property(
type = PropertyType.STRING_ARRAY,
description = "Custom Pickup Conditions for Blocks",
validationRegex = "([a-zA-Z0-9_*\\-:]+(?:\\[[^\\]]*\\])?)\\(([\\w_]+)\\)"
)
public String[] customPickupConditionsBlocks = {};
@Property(
type = PropertyType.STRING_ARRAY,
description = "Custom Pickup Conditions for Entities",
validationRegex = "([a-zA-Z0-9_*\\-:]+(?:\\[[^\\]]*\\])?)\\(([\\w_]+)\\)"
)
public String[] customPickupConditionsEntities = {};
}
}
@Config("carryon-client")
public static class Client
{
@Property(
type = PropertyType.BOOLEAN,
description = "If the front of the Tile Entities should face the player or should face outward"
)
public boolean facePlayer = false;
@Property(
type = PropertyType.BOOLEAN,
description = "If Entities should be rotated sideways when carried"
)
public boolean rotateEntitiesSideways = false;
@Property(
type = PropertyType.BOOLEAN,
description = "Arms should render on sides when carrying. Set to false if you experience issues with mods that replace the player model (like MoBends, etc)"
)
public boolean renderArms = true;
@Property(
type = PropertyType.STRING_ARRAY,
description = "Model Overrides based on NBT or Meta. Advanced users only! Read about the format here: https://github.com/Tschipp/CarryOn/wiki/Model-Override-Config",
validationRegex = "([a-zA-Z0-9_]+:[a-zA-Z0-9_]+(?:\\[[^\\]]*\\])?(?:\\{[^}]*\\})?)(?:;(\\d+))?->(?:\\((item|block)\\))?([a-zA-Z0-9_]+:[a-zA-Z0-9_]+(?:\\[[^\\]]*\\])?(?:\\{[^}]*\\})?)(?:;(\\d+))?"
)
public String[] modelOverrides = {
"minecraft:redstone_wire->(item)minecraft:redstone",
"minecraft:bamboo_sapling->(block)minecraft:bamboo",
"minecraft:candle_cake->(block)minecraft:cake"
};
}
}

View File

@ -0,0 +1,236 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.common.config;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.Identifier;
import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.properties.Property;
import tschipp.carryon.Constants;
import tschipp.carryon.utils.StringHelper;
import java.util.*;
import java.util.stream.Collectors;
public class ListHandler {
private static Set<String> FORBIDDEN_TILES = new HashSet<>();
private static Set<String> FORBIDDEN_ENTITIES = new HashSet<>();
private static Set<String> ALLOWED_ENTITIES = new HashSet<>();
private static Set<String> ALLOWED_TILES = new HashSet<>();
private static Set<String> FORBIDDEN_STACKING = new HashSet<>();
private static Set<String> ALLOWED_STACKING = new HashSet<>();
private static List<TagKey<Block>> FORBIDDEN_TILES_TAGS = new ArrayList<>();
private static List<TagKey<EntityType<?>>> FORBIDDEN_ENTITIES_TAGS = new ArrayList<>();
private static List<TagKey<EntityType<?>>> ALLOWED_ENTITIES_TAGS = new ArrayList<>();
private static List<TagKey<Block>> ALLOWED_TILES_TAGS = new ArrayList<>();
private static List<TagKey<EntityType<?>>> FORBIDDEN_STACKING_TAGS = new ArrayList<>();
private static List<TagKey<EntityType<?>>> ALLOWED_STACKING_TAGS = new ArrayList<>();
private static Set<Property<?>> PROPERTY_EXCEPTION_CLASSES = new HashSet<>();
public static boolean isPermitted(Block block)
{
if(Constants.COMMON_CONFIG.settings.useWhitelistBlocks)
return doCheck(block, ALLOWED_TILES, ALLOWED_TILES_TAGS);
else
return !doCheck(block, FORBIDDEN_TILES, FORBIDDEN_TILES_TAGS);
}
public static boolean isPermitted(Entity entity)
{
if(Constants.COMMON_CONFIG.settings.useWhitelistEntities)
return doCheck(entity, ALLOWED_ENTITIES, ALLOWED_ENTITIES_TAGS);
else
return !doCheck(entity, FORBIDDEN_ENTITIES, FORBIDDEN_ENTITIES_TAGS);
}
public static boolean isStackingPermitted(Entity entity)
{
if(Constants.COMMON_CONFIG.settings.useWhitelistStacking)
return doCheck(entity, ALLOWED_STACKING, ALLOWED_STACKING_TAGS);
else
return !doCheck(entity, FORBIDDEN_STACKING, FORBIDDEN_STACKING_TAGS);
}
public static boolean isPropertyException(Property<?> prop)
{
return PROPERTY_EXCEPTION_CLASSES.contains(prop);
}
private static boolean doCheck(Block block, Set<String> regular, List<TagKey<Block>> tags)
{
String name = BuiltInRegistries.BLOCK.getKey(block).toString();
if(regular.contains(name))
return true;
for(TagKey<Block> tag : tags)
if(block.defaultBlockState().is(tag))
return true;
return false;
}
private static boolean doCheck(Entity entity, Set<String> regular, List<TagKey<EntityType<?>>> tags)
{
String name = BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString();
if(regular.contains(name))
return true;
for(TagKey<EntityType<?>> tag : tags)
if(entity.getType().is(tag))
return true;
return false;
}
public static void initConfigLists()
{
FORBIDDEN_ENTITIES.clear();
FORBIDDEN_ENTITIES_TAGS.clear();
FORBIDDEN_STACKING.clear();
FORBIDDEN_STACKING_TAGS.clear();
FORBIDDEN_TILES.clear();
FORBIDDEN_TILES_TAGS.clear();
ALLOWED_ENTITIES.clear();
ALLOWED_ENTITIES_TAGS.clear();
ALLOWED_STACKING.clear();
ALLOWED_STACKING_TAGS.clear();
ALLOWED_TILES.clear();
ALLOWED_TILES_TAGS.clear();
PROPERTY_EXCEPTION_CLASSES.clear();
Map<Identifier, TagKey<Block>> blocktags = BuiltInRegistries.BLOCK.listTagIds().collect(Collectors.toMap(t -> t.location(), t -> t));
Map<Identifier, TagKey<EntityType<?>>> entitytags = BuiltInRegistries.ENTITY_TYPE.listTagIds().collect(Collectors.toMap(t -> t.location(), t -> t));
List<String> forbidden = new ArrayList<>(List.of(Constants.COMMON_CONFIG.blacklist.forbiddenTiles));
forbidden.add("#carryon:block_blacklist");
addWithWildcards(forbidden, FORBIDDEN_TILES, BuiltInRegistries.BLOCK, blocktags, FORBIDDEN_TILES_TAGS);
List<String> forbiddenEntity = new ArrayList<>(List.of(Constants.COMMON_CONFIG.blacklist.forbiddenEntities));
forbiddenEntity.add("#carryon:entity_blacklist");
addWithWildcards(forbiddenEntity, FORBIDDEN_ENTITIES, BuiltInRegistries.ENTITY_TYPE, entitytags, FORBIDDEN_ENTITIES_TAGS);
List<String> allowedEntities = new ArrayList<>(List.of(Constants.COMMON_CONFIG.whitelist.allowedEntities));
allowedEntities.add("#carryon:entity_whitelist");
addWithWildcards(allowedEntities, ALLOWED_ENTITIES, BuiltInRegistries.ENTITY_TYPE, entitytags, ALLOWED_ENTITIES_TAGS);
List<String> allowedBlocks = new ArrayList<>(List.of(Constants.COMMON_CONFIG.whitelist.allowedBlocks));
allowedBlocks.add("#carryon:block_whitelist");
addWithWildcards(allowedBlocks, ALLOWED_TILES, BuiltInRegistries.BLOCK, blocktags, ALLOWED_TILES_TAGS);
List<String> forbiddenStacking = new ArrayList<>(List.of(Constants.COMMON_CONFIG.blacklist.forbiddenStacking));
forbiddenStacking.add("#carryon:stacking_blacklist");
addWithWildcards(forbiddenStacking, FORBIDDEN_STACKING, BuiltInRegistries.ENTITY_TYPE, entitytags, FORBIDDEN_STACKING_TAGS);
List<String> allowedStacking = new ArrayList<>(List.of(Constants.COMMON_CONFIG.whitelist.allowedStacking));
allowedStacking.add("#carryon:stacking_whitelist");
addWithWildcards(allowedStacking, ALLOWED_STACKING, BuiltInRegistries.ENTITY_TYPE, entitytags, ALLOWED_STACKING_TAGS);
for(String propString : Constants.COMMON_CONFIG.settings.placementStateExceptions)
{
if(!propString.contains("[") || !propString.contains("]"))
continue;
String name = propString.substring(0, propString.indexOf("["));
String props = propString.substring(propString.indexOf("[") + 1, propString.indexOf("]"));
Block blk = BuiltInRegistries.BLOCK.get(Identifier.parse(name)).get().value();
for(String propName : props.split(",")) {
for (Property<?> prop : blk.defaultBlockState().getProperties()) {
if (prop.getName().equals(propName))
PROPERTY_EXCEPTION_CLASSES.add(prop);
}
}
}
}
private static <T> void addTag(String tag, Map<Identifier, TagKey<T>> tagMap, List<TagKey<T>> tags) {
String sub = tag.substring(1);
TagKey<T> t = tagMap.get(Identifier.parse(sub));
if (t != null)
tags.add(t);
}
private static <T> void addWithWildcards(List<String> entries, Set<String> toAddTo, Registry<T> registry, Map<Identifier, TagKey<T>> tags, List<TagKey<T>> toAddTags) {
Identifier[] keys = registry.keySet().toArray(new Identifier[0]);
for (int i = 0; i < entries.size(); i++)
{
String curr = entries.get(i);
if (!curr.startsWith("#"))
{
if (curr.contains("*"))
{
String[] filter = curr.replace("*", ",").split(",");
for (Identifier key : keys)
{
if (containsAll(key.toString(), filter))
{
toAddTo.add(key.toString());
}
}
}
else
toAddTo.add(curr);
}
else
addTag(curr, tags, toAddTags);
}
}
public static boolean containsAll(String str, String... strings)
{
return StringHelper.matchesWildcards(str, strings);
}
public static void addForbiddenTiles(String toAdd)
{
FORBIDDEN_TILES.add(toAdd);
}
public static void addForbiddenEntities(String toAdd)
{
FORBIDDEN_ENTITIES.add(toAdd);
}
public static void addForbiddenStacking(String toAdd)
{
FORBIDDEN_STACKING.add(toAdd);
}
public static void addAllowedTiles(String toAdd)
{
ALLOWED_TILES.add(toAdd);
}
public static void addAllowedEntities(String toAdd)
{
ALLOWED_ENTITIES.add(toAdd);
}
public static void addAllowedStacking(String toAdd)
{
ALLOWED_ENTITIES.add(toAdd);
}
}

View File

@ -0,0 +1,143 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.common.pickupcondition;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import net.minecraft.commands.arguments.blocks.BlockStateParser;
import net.minecraft.commands.arguments.blocks.BlockStateParser.BlockResult;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Property;
import tschipp.carryon.platform.Services;
import tschipp.carryon.utils.StringHelper;
import java.util.Map;
public class PickupCondition
{
public static Codec<PickupCondition> CODEC = Codec.STRING.comapFlatMap(PickupCondition::of, pickupCondition -> pickupCondition.str);
private String str, cond, match;
private boolean wildcards;
private PickupCondition(String str, String cond, String match)
{
this.str = str;
this.cond = cond;
this.match = match;
}
public static DataResult<PickupCondition> of(String str)
{
if(!(str.contains("(") && str.endsWith(")")))
return DataResult.error(() -> "Error while parsing: "+ str +". Pickup Condition must contain proper brackets.");
String cond = str.substring(str.indexOf("(") + 1, str.length()-1);
String match = str.substring(0, str.indexOf("("));
PickupCondition condition = new PickupCondition(str, cond, match);
if(match.contains("*"))
condition.wildcards = true;
return DataResult.success(condition);
}
public boolean matches(BlockState state)
{
if(wildcards)
{
String name = match.contains("[") ? match.substring(0, match.indexOf("[")) : match;
String[] split = name.replace("*", ",").split(",");
String stateName = BuiltInRegistries.BLOCK.getKey(state.getBlock()).toString();
if(StringHelper.matchesWildcards(stateName, split))
{
if(match.contains("["))
{
stateName = stateName + match.substring(match.indexOf("["));
BlockResult result = parseState(stateName);
return matchesProperties(state, result.properties());
}
else
return true;
}
else
return false;
}
else
{
BlockResult res = parseState(match);
return res.blockState().getBlock() == state.getBlock() && matchesProperties(state, res.properties());
}
}
public boolean matches(Entity entity)
{
String entityName = BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString();
if(wildcards)
{
String[] split = match.replace("*", ",").split(",");
return StringHelper.matchesWildcards(entityName, split);
}
else
return entityName.equals(match);
}
public String getCondition()
{
return cond;
}
public boolean isFulfilled(ServerPlayer player)
{
return Services.GAMESTAGES.hasStage(player, cond);
}
private BlockResult parseState(String state)
{
try {
BlockResult result = BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK, state, false);
return result;
} catch (CommandSyntaxException e) {
e.printStackTrace();
}
return null;
}
private boolean matchesProperties(BlockState state, Map<Property<?>, Comparable<?>> props)
{
for(var entry : props.entrySet())
{
var val = state.getValue(entry.getKey());
if(val != entry.getValue())
return false;
}
return true;
}
}

View File

@ -0,0 +1,91 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.common.pickupcondition;
import com.mojang.serialization.DataResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.state.BlockState;
import tschipp.carryon.Constants;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class PickupConditionHandler
{
private static final List<PickupCondition> BLOCK_CONDITIONS = new ArrayList<>();
private static final List<PickupCondition> ENTITY_CONDITIONS = new ArrayList<>();
public static void initPickupConditions()
{
BLOCK_CONDITIONS.clear();
ENTITY_CONDITIONS.clear();
for(String cond : Constants.COMMON_CONFIG.customPickupConditions.customPickupConditionsBlocks)
{
DataResult<PickupCondition> res = PickupCondition.of(cond);
if(res.result().isPresent())
{
PickupCondition pickupCondition = res.result().get();
BLOCK_CONDITIONS.add(pickupCondition);
}
else
{
Constants.LOG.debug("Error while parsing Pickup Conditions: " + res.error().get().message());
}
}
for(String cond : Constants.COMMON_CONFIG.customPickupConditions.customPickupConditionsEntities)
{
DataResult<PickupCondition> res = PickupCondition.of(cond);
if(res.result().isPresent())
{
PickupCondition pickupCondition = res.result().get();
ENTITY_CONDITIONS.add(pickupCondition);
}
else
{
Constants.LOG.debug("Error while parsing Pickup Conditions: " + res.error().get().message());
}
}
}
public static Optional<PickupCondition> getPickupCondition(BlockState state)
{
for(PickupCondition cond : BLOCK_CONDITIONS)
{
if(cond.matches(state))
return Optional.of(cond);
}
return Optional.empty();
}
public static Optional<PickupCondition> getPickupCondition(Entity entity)
{
for(PickupCondition cond : ENTITY_CONDITIONS)
{
if(cond.matches(entity))
return Optional.of(cond);
}
return Optional.empty();
}
}

View File

@ -0,0 +1,205 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.common.scripting;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.block.Block;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectBlock;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectEntity;
import tschipp.carryon.common.scripting.Matchables.*;
import java.util.Optional;
public record CarryOnScript(
long priority,
ScriptObject scriptObject,
ScriptConditions scriptConditions,
ScriptRender scriptRender,
ScriptEffects scriptEffects,
boolean overrideChecks)
{
public boolean isValid()
{
return (isBlock() ^ isEntity()) && (scriptConditions != ScriptConditions.EMPTY || scriptRender != ScriptRender.EMPTY || scriptEffects != ScriptEffects.EMPTY || overrideChecks);
}
public boolean isBlock()
{
return scriptObject.block() != ScriptObjectBlock.EMPTY;
}
public boolean isEntity()
{
return scriptObject.entity() != ScriptObjectEntity.EMPTY;
}
public static final Codec<CarryOnScript> CODEC = RecordCodecBuilder.create(instance -> // Given an instance
instance.group(
Codec.LONG.optionalFieldOf("priority", 0L).forGetter(CarryOnScript::priority),
ScriptObject.CODEC.fieldOf("object").forGetter(CarryOnScript::scriptObject),
ScriptConditions.CODEC.optionalFieldOf("conditions", ScriptConditions.EMPTY).forGetter(CarryOnScript::scriptConditions),
ScriptRender.CODEC.optionalFieldOf("render", ScriptRender.EMPTY).forGetter(CarryOnScript::scriptRender),
ScriptEffects.CODEC.optionalFieldOf("effects", ScriptEffects.EMPTY).forGetter(CarryOnScript::scriptEffects),
Codec.BOOL.optionalFieldOf("override_checks", false).forGetter(CarryOnScript::overrideChecks)
).apply(instance, CarryOnScript::new)
);
public boolean fulfillsConditions(ServerPlayer player)
{
ScriptConditions cond = this.scriptConditions();
boolean achievement = cond.conditionAchievement.matches(player);
boolean gamemode = cond.conditionGamemode.matches(player.gameMode.getGameModeForPlayer().getId());
boolean gamestage = cond.conditionGamestage.matches(player);
boolean position = cond.conditionPosition.matches(player);
boolean xp = cond.conditionXp.matches(player.experienceLevel);
boolean scoreboard = cond.conditionScoreboard.matches(player);
boolean effects = cond.conditionEffects.matches(player);
return achievement && gamemode && gamestage && position && xp && scoreboard && effects;
}
public record ScriptObject(ScriptObjectBlock block, ScriptObjectEntity entity)
{
public static final Codec<ScriptObject> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
ScriptObjectBlock.CODEC.optionalFieldOf("block", ScriptObjectBlock.EMPTY).forGetter(ScriptObject::block),
ScriptObjectEntity.CODEC.optionalFieldOf("entity", ScriptObjectEntity.EMPTY).forGetter(ScriptObject::entity)
).apply(instance, ScriptObject::new)
);
public record ScriptObjectBlock(
Optional<ResourceKey<Block>> typeNameBlock,
NumberBoundCondition typeHardness,
NumberBoundCondition typeResistance,
NBTCondition typeBlockTag
){
public static final ScriptObjectBlock EMPTY = new ScriptObjectBlock(Optional.empty(), NumberBoundCondition.NONE, NumberBoundCondition.NONE, NBTCondition.NONE);
public static final Codec<ScriptObjectBlock> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
ResourceKey.codec(Registries.BLOCK).optionalFieldOf("name").forGetter(ScriptObjectBlock::typeNameBlock),
NumberBoundCondition.CODEC.optionalFieldOf("hardness", NumberBoundCondition.NONE).forGetter(ScriptObjectBlock::typeHardness),
NumberBoundCondition.CODEC.optionalFieldOf("resistance", NumberBoundCondition.NONE).forGetter(ScriptObjectBlock::typeResistance),
NBTCondition.CODEC.optionalFieldOf("nbt", NBTCondition.NONE).forGetter(ScriptObjectBlock::typeBlockTag)
).apply(instance, ScriptObjectBlock::new)
);
}
public record ScriptObjectEntity(
Optional<ResourceKey<EntityType<?>>> typeNameEntity,
NumberBoundCondition typeHealth,
NumberBoundCondition typeHeight,
NumberBoundCondition typeWidth,
NBTCondition typeEntityTag
){
public static final ScriptObjectEntity EMPTY = new ScriptObjectEntity(Optional.empty(), NumberBoundCondition.NONE, NumberBoundCondition.NONE, NumberBoundCondition.NONE, NBTCondition.NONE);
public static final Codec<ScriptObjectEntity> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
ResourceKey.codec(Registries.ENTITY_TYPE).optionalFieldOf("name").forGetter(ScriptObjectEntity::typeNameEntity),
NumberBoundCondition.CODEC.optionalFieldOf("health", NumberBoundCondition.NONE).forGetter(ScriptObjectEntity::typeHealth),
NumberBoundCondition.CODEC.optionalFieldOf("height", NumberBoundCondition.NONE).forGetter(ScriptObjectEntity::typeHeight),
NumberBoundCondition.CODEC.optionalFieldOf("width", NumberBoundCondition.NONE).forGetter(ScriptObjectEntity::typeWidth),
NBTCondition.CODEC.optionalFieldOf("nbt", NBTCondition.NONE).forGetter(ScriptObjectEntity::typeEntityTag)
).apply(instance, ScriptObjectEntity::new)
);
}
}
public record ScriptConditions(
GamestageCondition conditionGamestage,
AdvancementCondition conditionAchievement,
NumberBoundCondition conditionXp,
NumberBoundCondition conditionGamemode,
ScoreboardCondition conditionScoreboard,
PositionCondition conditionPosition,
EffectsCondition conditionEffects
){
public static final ScriptConditions EMPTY = new ScriptConditions(GamestageCondition.NONE, AdvancementCondition.NONE, NumberBoundCondition.NONE, NumberBoundCondition.NONE, ScoreboardCondition.NONE, PositionCondition.NONE, EffectsCondition.NONE);
public static final Codec<ScriptConditions> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
GamestageCondition.CODEC.optionalFieldOf("gamestage", GamestageCondition.NONE).forGetter(ScriptConditions::conditionGamestage),
AdvancementCondition.CODEC.optionalFieldOf("advancement", AdvancementCondition.NONE).forGetter(ScriptConditions::conditionAchievement),
NumberBoundCondition.CODEC.optionalFieldOf("xp", NumberBoundCondition.NONE).forGetter(ScriptConditions::conditionXp),
NumberBoundCondition.CODEC.optionalFieldOf("gamemode", NumberBoundCondition.NONE).forGetter(ScriptConditions::conditionGamemode),
ScoreboardCondition.CODEC.optionalFieldOf("scoreboard", ScoreboardCondition.NONE).forGetter(ScriptConditions::conditionScoreboard),
PositionCondition.CODEC.optionalFieldOf("position", PositionCondition.NONE).forGetter(ScriptConditions::conditionPosition),
EffectsCondition.CODEC.optionalFieldOf("effects", EffectsCondition.NONE).forGetter(ScriptConditions::conditionEffects)
).apply(instance, ScriptConditions::new)
);
}
public record ScriptRender(
Optional<ResourceKey<Block>> renderNameBlock,
Optional<ResourceKey<EntityType<?>>> renderNameEntity,
Optional<CompoundTag> renderNBT,
OptionalVec3 renderTranslation,
OptionalVec3 renderRotation,
OptionalVec3 renderscale,
OptionalVec3 renderRotationLeftArm,
OptionalVec3 renderRotationRightArm,
boolean renderLeftArm,
boolean renderRightArm
){
public static final ScriptRender EMPTY = new ScriptRender(Optional.empty(), Optional.empty(), Optional.empty(), OptionalVec3.NONE, OptionalVec3.NONE, OptionalVec3.NONE, OptionalVec3.NONE, OptionalVec3.NONE, true, true);
public static final Codec<ScriptRender> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
ResourceKey.codec(Registries.BLOCK).optionalFieldOf("name_block").forGetter(ScriptRender::renderNameBlock),
ResourceKey.codec(Registries.ENTITY_TYPE).optionalFieldOf("name_entity").forGetter(ScriptRender::renderNameEntity),
CompoundTag.CODEC.optionalFieldOf("nbt").forGetter(ScriptRender::renderNBT),
OptionalVec3.CODEC.optionalFieldOf("translation", OptionalVec3.NONE).forGetter(ScriptRender::renderTranslation),
OptionalVec3.CODEC.optionalFieldOf("rotation", OptionalVec3.NONE).forGetter(ScriptRender::renderRotation),
OptionalVec3.CODEC.optionalFieldOf("scale", OptionalVec3.NONE).forGetter(ScriptRender::renderscale),
OptionalVec3.CODEC.optionalFieldOf("rotation_left_arm", OptionalVec3.NONE).forGetter(ScriptRender::renderRotationLeftArm),
OptionalVec3.CODEC.optionalFieldOf("rotation_right_arm", OptionalVec3.NONE).forGetter(ScriptRender::renderRotationRightArm),
Codec.BOOL.optionalFieldOf("render_left_arm", true).forGetter(ScriptRender::renderLeftArm),
Codec.BOOL.optionalFieldOf("render_right_arm", true).forGetter(ScriptRender::renderRightArm)
).apply(instance, ScriptRender::new)
);
}
public record ScriptEffects(
String commandInit,
String commandLoop,
String commandPlace
){
public static final ScriptEffects EMPTY = new ScriptEffects("", "", "");
public static final Codec<ScriptEffects> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
Codec.STRING.optionalFieldOf("commandPickup", "").forGetter(ScriptEffects::commandInit),
Codec.STRING.optionalFieldOf("commandLoop", "").forGetter(ScriptEffects::commandLoop),
Codec.STRING.optionalFieldOf("commandPlace", "").forGetter(ScriptEffects::commandPlace)
).apply(instance, ScriptEffects::new)
);
}
}

View File

@ -0,0 +1,354 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.common.scripting;
import com.mojang.serialization.Codec;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.advancements.AdvancementHolder;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.resources.Identifier;
import net.minecraft.server.ServerAdvancementManager;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.Objective;
import net.minecraft.world.scores.Scoreboard;
import tschipp.carryon.platform.Services;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
public final class Matchables
{
public interface Matchable<T>
{
boolean matches(T elem);
}
private static float getValueFromStringOrDefault(String toGetFrom, String key, float defaultVal)
{
Optional<Float> val = getValueFromString(toGetFrom, key);
return val.orElse(defaultVal);
}
private static Optional<Float> getValueFromString(String toGetFrom, String key)
{
if (toGetFrom == null || toGetFrom.isEmpty())
return Optional.empty();
String[] s = toGetFrom.split(",");
for (String string : s)
{
if (string.contains(key) && string.contains("="))
{
float numb = 0;
string = string.replace(key + "=", "");
try
{
numb = Float.parseFloat(string);
}
catch (Exception e)
{
}
return Optional.of(numb);
}
}
return Optional.empty();
}
public record NumberBoundCondition(String bounds) implements Matchable<Number>
{
public static final Codec<NumberBoundCondition> CODEC = Codec.STRING.xmap(NumberBoundCondition::new, NumberBoundCondition::bounds);
public static final NumberBoundCondition NONE = new NumberBoundCondition("");
@Override
public boolean matches(Number num)
{
double number = num.doubleValue();
if (bounds == null || bounds.isEmpty())
return true;
try
{
if (bounds.contains("<="))
return number <= Double.parseDouble(bounds.replace("<=", ""));
if (bounds.contains(">="))
return number >= Double.parseDouble(bounds.replace(">=", ""));
if (bounds.contains("<"))
return number < Double.parseDouble(bounds.replace("<", ""));
if (bounds.contains(">"))
return number > Double.parseDouble(bounds.replace(">", ""));
if (bounds.contains("="))
return number == Double.parseDouble(bounds.replace("=", ""));
else
return number == Double.parseDouble(bounds);
}
catch (Exception e)
{
throw new RuntimeException("Error while parsing Number bound for string: "+ bounds + ". Error: " + e.getMessage());
}
}
}
public record AdvancementCondition(String advancement) implements Matchable<ServerPlayer>
{
public static final Codec<AdvancementCondition> CODEC = Codec.STRING.xmap(AdvancementCondition::new, AdvancementCondition::advancement);
public static final AdvancementCondition NONE = new AdvancementCondition("");
@Override
public boolean matches(ServerPlayer player)
{
ServerAdvancementManager manager = player.level().getServer().getAdvancements();
AdvancementHolder adv = manager.get(Identifier.parse(advancement.isEmpty() ? "" : advancement));
boolean achievement = adv == null ? true : player.getAdvancements().getOrStartProgress(adv).isDone();
return achievement;
}
}
public record GamestageCondition(String gamestage) implements Matchable<ServerPlayer>
{
public static final Codec<GamestageCondition> CODEC = Codec.STRING.xmap(GamestageCondition::new, GamestageCondition::gamestage);
public static final GamestageCondition NONE = new GamestageCondition("");
@Override
public boolean matches(ServerPlayer player)
{
if(!Services.PLATFORM.isModLoaded("gamestages"))
return true;
if(gamestage == null || gamestage.isEmpty())
return true;
return Services.GAMESTAGES.hasStage(player, gamestage);
}
}
public record ScoreboardCondition(String cond) implements Matchable<ServerPlayer>
{
public static final Codec<ScoreboardCondition> CODEC = Codec.STRING.xmap(ScoreboardCondition::new, ScoreboardCondition::cond);
public static final ScoreboardCondition NONE = new ScoreboardCondition("");
@Override
public boolean matches(ServerPlayer player)
{
if (cond == null || cond.isEmpty())
return true;
Scoreboard score = player.level().getScoreboard();
String numb;
String scorename;
int iE = cond.indexOf("=");
int iG = cond.indexOf(">");
int iL = cond.indexOf("<");
if (iG == -1 || (iE < iG && iL == -1 || iE < iL && iE != -1))
numb = cond.substring(iE);
else if (iE == -1 || (iG < iE && iL == -1 || iG < iL && iG != -1))
numb = cond.substring(iG);
else
numb = cond.substring(iL);
scorename = cond.replace(numb, "");
Object2IntMap<Objective> scores = score.listPlayerScores(player);
int scoreVal = scores.getInt(score.getObjective(scorename));
return new NumberBoundCondition(numb).matches(scoreVal);
}
}
public record PositionCondition(String cond) implements Matchable<ServerPlayer>
{
public static final Codec<PositionCondition> CODEC = Codec.STRING.xmap(PositionCondition::new, PositionCondition::cond);
public static final PositionCondition NONE = new PositionCondition("");
@Override
public boolean matches(ServerPlayer elem)
{
if (cond == null || cond.isEmpty())
return true;
BlockPos blockpos = new BlockPos((int) getValueFromStringOrDefault(cond, "x", 0), (int) getValueFromStringOrDefault(cond, "y", 0), (int) getValueFromStringOrDefault(cond, "z", 0));
BlockPos expand = new BlockPos((int) getValueFromStringOrDefault(cond, "dx", 0), (int) getValueFromStringOrDefault(cond, "dy", 0), (int) getValueFromStringOrDefault(cond, "dz", 0));
BlockPos expanded = blockpos.offset(expand);
BlockPos pos = elem.blockPosition();
boolean x = pos.getX() >= blockpos.getX() && pos.getX() <= expanded.getX() || blockpos.getX() == 0;
boolean y = pos.getY() >= blockpos.getY() && pos.getY() <= expanded.getY() || blockpos.getY() == 0;
boolean z = pos.getZ() >= blockpos.getZ() && pos.getZ() <= expanded.getZ() || blockpos.getZ() == 0;
return x && y && z;
}
}
public record EffectsCondition(String effects) implements Matchable<ServerPlayer>
{
public static final Codec<EffectsCondition> CODEC = Codec.STRING.xmap(EffectsCondition::new, EffectsCondition::effects);
public static final EffectsCondition NONE = new EffectsCondition("");
@Override
public boolean matches(ServerPlayer player)
{
if (effects == null || effects.isEmpty())
return true;
Collection<MobEffectInstance> fx = player.getActiveEffects();
String[] potions = effects.split(",");
List<String> names = new ArrayList<>();
List<Integer> levels = new ArrayList<>();
for (String pot : potions)
{
if (pot.contains("#"))
{
String level = pot.substring(pot.indexOf("#"));
String name = pot.substring(0, pot.indexOf("#"));
level = level.replace("#", "");
int lev = 0;
try
{
lev = Integer.parseInt(level);
}
catch (Exception e)
{
}
levels.add(lev);
names.add(name);
}
else
{
levels.add(0);
names.add(pot);
}
}
int matches = 0;
for (MobEffectInstance effect : fx)
{
int amp = effect.getAmplifier();
String name = effect.getEffect().getRegisteredName();
if (names.contains(name))
{
int idx = names.indexOf(name);
int lev = levels.get(idx);
if (lev <= amp)
matches++;
}
}
return matches == potions.length;
}
}
public record NBTCondition(CompoundTag tag) implements Matchable<CompoundTag>
{
public static final Codec<NBTCondition> CODEC = CompoundTag.CODEC.xmap(NBTCondition::new, NBTCondition::tag);
public static final NBTCondition NONE = new NBTCondition(new CompoundTag());
@Override
public boolean matches(CompoundTag other)
{
if(other == null)
return true;
return NbtUtils.compareNbt(tag, other, true);
}
}
public static class OptionalVec3 {
public static final Codec<OptionalVec3> CODEC = Codec.STRING.xmap(OptionalVec3::new, OptionalVec3::source);
public static final OptionalVec3 NONE = new OptionalVec3("");
String source;
Vec3 vec;
boolean x, y, z;
public OptionalVec3(String source)
{
this.source = source;
Optional<Float> xOpt = getValueFromString(source, "x");
Optional<Float> yOpt = getValueFromString(source, "y");
Optional<Float> zOpt = getValueFromString(source, "z");
float x = 0, y = 0, z = 0;
if(xOpt.isPresent()) {
x = xOpt.get();
this.x = true;
}
if(yOpt.isPresent()) {
y = yOpt.get();
this.y = true;
}
if(zOpt.isPresent()) {
z = zOpt.get();
this.z = true;
}
vec = new Vec3(x, y, z);
}
private String source()
{
return source;
}
/**
* Gets the contained optional vector. Nonexisting numbers are set to 0.
*/
public Vec3 getVec()
{
return vec;
}
public Vec3 getVec(double dX, double dY, double dZ)
{
double x = !this.x ? dX : vec.x;
double y = !this.y ? dY : vec.y;
double z = !this.z ? dZ : vec.z;
return new Vec3(x, y, z);
}
}
}

View File

@ -0,0 +1,113 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.common.scripting;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.TagValueOutput;
import tschipp.carryon.Constants;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectBlock;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectEntity;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class ScriptManager
{
public static final List<CarryOnScript> SCRIPTS = new ArrayList<>();
public static Optional<CarryOnScript> inspectBlock(BlockState state, Level level, BlockPos pos, @Nullable CompoundTag tag)
{
if (!Constants.COMMON_CONFIG.settings.useScripts)
return Optional.empty();
Block block = state.getBlock();
float hardness = state.getDestroySpeed(level, pos);
float resistance = block.getExplosionResistance();
for (CarryOnScript script : SCRIPTS)
{
if (script.isBlock() && matchesAll(script, block, hardness, resistance, tag))
return Optional.of(script);
}
return Optional.empty();
}
public static Optional<CarryOnScript> inspectEntity(Entity entity)
{
if (!Constants.COMMON_CONFIG.settings.useScripts)
return Optional.empty();
float height = entity.getBbHeight();
float width = entity.getBbWidth();
float health = entity instanceof LivingEntity ? ((LivingEntity) entity).getHealth() : 0.0f;
TagValueOutput output = TagValueOutput.createWithContext(new ProblemReporter.ScopedCollector(Constants.LOG), entity.registryAccess());
entity.save(output);
CompoundTag tag = output.buildResult();
for (CarryOnScript script : SCRIPTS)
{
if (script.isEntity() && matchesAll(script, entity, height, width, health, tag))
return Optional.of(script);
}
return Optional.empty();
}
private static boolean matchesAll(CarryOnScript script, Entity entity, float height, float width, float health, CompoundTag tag)
{
ScriptObjectEntity scEntity = script.scriptObject().entity();
boolean matchname = true;
if(scEntity.typeNameEntity().isPresent())
matchname = entity.getType().equals(BuiltInRegistries.ENTITY_TYPE.get(scEntity.typeNameEntity().get()));
boolean matchheight = scEntity.typeHeight().matches(height);
boolean matchwidth = scEntity.typeWidth().matches(width);
boolean matchhealth = scEntity.typeHealth().matches(health);
boolean matchnbt = scEntity.typeEntityTag().matches(tag);
return matchname && matchheight && matchwidth && matchhealth && matchnbt;
}
private static boolean matchesAll(CarryOnScript script, Block block, float hardness, float resistance, CompoundTag nbt)
{
ScriptObjectBlock scBlock = script.scriptObject().block();
boolean matchblock = true;
if(scBlock.typeNameBlock().isPresent())
matchblock = block == BuiltInRegistries.BLOCK.get(scBlock.typeNameBlock().get()).get().value();
boolean matchnbt = scBlock.typeBlockTag().matches(nbt);
boolean matchhardness = scBlock.typeHardness().matches(hardness);
boolean matchresistance = scBlock.typeResistance().matches(resistance);
return matchnbt && matchblock && matchhardness && matchresistance;
}
}

View File

@ -0,0 +1,72 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.common.scripting;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.FileToIdConverter;
import net.minecraft.resources.Identifier;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
import net.minecraft.util.profiling.ProfilerFiller;
import org.jetbrains.annotations.NotNull;
import tschipp.carryon.Constants;
import tschipp.carryon.networking.clientbound.ClientboundSyncScriptsPacket;
import tschipp.carryon.platform.Services;
import java.util.Map;
public class ScriptReloadListener extends SimpleJsonResourceReloadListener<CarryOnScript>
{
public ScriptReloadListener()
{
super(CarryOnScript.CODEC, FileToIdConverter.json("carryon/scripts"));
}
@Override
protected void apply(Map<Identifier, CarryOnScript> scripts, @NotNull ResourceManager resourceManager, @NotNull ProfilerFiller profilerFiller)
{
ScriptManager.SCRIPTS.clear();
scripts.forEach((path, script) -> {
if (script.isValid())
ScriptManager.SCRIPTS.add(script);
});
ScriptManager.SCRIPTS.sort((s1, s2) -> Long.compare(s2.priority(), s1.priority()));
}
public static void syncScriptsWithClient(ServerPlayer player)
{
if (player != null)
{
DataResult<Tag> result = Codec.list(CarryOnScript.CODEC).encodeStart(NbtOps.INSTANCE, ScriptManager.SCRIPTS);
Tag tag = result.getOrThrow(s -> {throw new RuntimeException("Error while synching Carry On Scripts: " + s);});
Services.PLATFORM.sendPacketToPlayer(Constants.PACKET_ID_SYNC_SCRIPTS, new ClientboundSyncScriptsPacket(tag), player);
}
}
}

View File

@ -0,0 +1,107 @@
package tschipp.carryon.compat;
import me.shedaniel.clothconfig2.api.ConfigBuilder;
import me.shedaniel.clothconfig2.api.ConfigCategory;
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
import me.shedaniel.clothconfig2.impl.builders.SubCategoryBuilder;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import tschipp.carryon.config.AnnotationData;
import tschipp.carryon.config.BuiltCategory;
import tschipp.carryon.config.BuiltConfig;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
public record ClothConfigCompat(BuiltConfig client, BuiltConfig common, Runnable onSave) {
public static Screen getConfigScreen(BuiltConfig client, BuiltConfig common, Screen parentScreen, Runnable onSave) {
ConfigBuilder builder = ConfigBuilder.create()
.setParentScreen(parentScreen)
.setTitle(Component.translatable("key.category.carryon.key.carry.category"));
buildConfigType(client, builder, "Client Config");
buildConfigType(common, builder, "Common Config");
builder.setSavingRunnable(onSave);
return builder.build();
}
private static void buildConfigType(BuiltConfig cfg, ConfigBuilder builder, String name) {
ConfigCategory configCategory = builder.getOrCreateCategory(Component.literal(name));
buildProperties(cfg, configCategory, builder, null);
}
private static void buildCategory(BuiltCategory category, ConfigCategory categoryBuilder, ConfigBuilder builder) {
ConfigEntryBuilder entryBuilder = builder.entryBuilder();
SubCategoryBuilder subBuilder = entryBuilder.startSubCategory(Component.translatable(category.translation));
buildProperties(category, categoryBuilder, builder, subBuilder);
}
private static void buildProperties(BuiltCategory category, ConfigCategory categoryBuilder, ConfigBuilder builder, @Nullable SubCategoryBuilder subBuilder) {
category.categories.forEach(cat -> {
buildCategory(cat, categoryBuilder, builder);
});
ConfigEntryBuilder entryBuilder = builder.entryBuilder();
category.properties.forEach(propertyData -> {
try {
AnnotationData data = propertyData.getData();
var entry =
switch (data.type()) {
case BOOLEAN ->
entryBuilder.startBooleanToggle(Component.literal(propertyData.getField().getName()), propertyData.getBoolean())
.setTooltip(Component.literal(data.description()))
.setDefaultValue(propertyData.getDefaultBoolean())
.setSaveConsumer((Consumer<Boolean>) propertyData.getSetter())
.build();
case INT ->
entryBuilder.startIntField(Component.literal(propertyData.getField().getName()), propertyData.getInt())
.setTooltip(Component.literal(data.description()))
.setDefaultValue(propertyData.getDefaultInt())
.setMin(data.min())
.setMax(data.max())
.setSaveConsumer((Consumer<Integer>) propertyData.getSetter())
.build();
case DOUBLE ->
entryBuilder.startDoubleField(Component.literal(propertyData.getField().getName()), propertyData.getDouble())
.setTooltip(Component.literal(data.description()))
.setDefaultValue(propertyData.getDefaultDouble())
.setMin(data.minD())
.setMax(data.maxD())
.setSaveConsumer((Consumer<Double>) propertyData.getSetter())
.build();
case STRING_ARRAY ->
entryBuilder.startStrList(Component.literal(propertyData.getField().getName()), List.of(propertyData.getStringArray()))
.setTooltip(Component.literal(data.description()))
.setInsertInFront(true)
.setDefaultValue(List.of(propertyData.getDefaultStringArray()))
.setCellErrorSupplier(str -> str.matches(data.validationRegex()) ? Optional.empty() : Optional.of(Component.literal("Invalid Format")))
.setSaveConsumer((Consumer<List<String>>) propertyData.getSetter())
.build();
default -> null;
};
if(subBuilder == null)
categoryBuilder.addEntry(entry);
else
subBuilder.add(entry);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
if(subBuilder != null)
categoryBuilder.addEntry(subBuilder.build());
}
}

View File

@ -0,0 +1,46 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.config;
import tschipp.carryon.config.annotations.Property;
import java.lang.reflect.Field;
public record AnnotationData(
PropertyType type,
String description,
int min, int max,
double minD, double maxD,
String validationRegex
) {
public static AnnotationData getData(Field field) {
Property annotation = field.getAnnotation(Property.class);
return new AnnotationData(
annotation.type(),
annotation.description(),
annotation.min(), annotation.max(),
annotation.minD(), annotation.maxD(),
annotation.validationRegex()
);
}
}

View File

@ -0,0 +1,60 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.config;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class BuiltCategory {
public final List<PropertyData> properties = new ArrayList<>();
public final List<BuiltCategory> categories = new ArrayList<>();
public final String categoryDesc;
public final String category;
public final String translation;
public BuiltCategory(String categoryDesc, String category, String translation) {
this.categoryDesc = categoryDesc;
this.category = category;
this.translation = translation;
}
public Optional<PropertyData> getProperty(String id) {
for (PropertyData property : properties) {
if (property.getId().equals(id)) {
return Optional.of(property);
}
}
return Optional.empty();
}
public Optional<BuiltCategory> getCategory(String id) {
for (BuiltCategory category : categories) {
if (category.category.equals(id)) {
return Optional.of(category);
}
}
return Optional.empty();
}
}

View File

@ -0,0 +1,31 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.config;
public class BuiltConfig extends BuiltCategory {
public final String fileName;
public BuiltConfig(String fileName) {
super(null, fileName, "key.carry.category");
this.fileName = fileName;
}
}

View File

@ -0,0 +1,86 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.config;
//Many Thanks to ThatGravyBoat for this template!
import net.minecraft.core.HolderLookup;
import tschipp.carryon.client.modeloverride.ModelOverrideHandler;
import tschipp.carryon.common.config.ListHandler;
import tschipp.carryon.common.pickupcondition.PickupConditionHandler;
import tschipp.carryon.config.annotations.Category;
import tschipp.carryon.config.annotations.Config;
import tschipp.carryon.config.annotations.Property;
import tschipp.carryon.platform.Services;
import java.lang.reflect.Field;
public class ConfigLoader {
public static void registerConfig(Object object) {
BuiltCategory category;
try {
category = buildCategory(null, object);
} catch (Exception e) {
e.printStackTrace();
category = null;
}
if (category instanceof BuiltConfig config) {
registerConfig(config);
} else {
throw new IllegalArgumentException("Config supplied does not have a @Config annotation");
}
}
public static void registerConfig(BuiltConfig config) {
Services.PLATFORM.registerConfig(config);
}
public static void onConfigLoaded(HolderLookup.Provider provider) {
ListHandler.initConfigLists();
PickupConditionHandler.initPickupConditions();
ModelOverrideHandler.initModelOverrides(provider);
}
public static BuiltCategory buildCategory(String categoryDesc, Object object) throws IllegalAccessException {
Class<?> configClass = object.getClass();
BuiltCategory category;
if (configClass.isAnnotationPresent(Config.class)) {
category = new BuiltConfig(configClass.getAnnotation(Config.class).value());
} else if (configClass.isAnnotationPresent(Category.class)) {
category = new BuiltCategory(categoryDesc, configClass.getAnnotation(Category.class).value(), configClass.getAnnotation(Category.class).translation());
} else {
throw new IllegalStateException("Config does not contain any @Config annotation or @Category");
}
for (Field field : configClass.getDeclaredFields()) {
if (field.isAnnotationPresent(Property.class) && field.canAccess(object)) {
PropertyType type = field.getAnnotation(Property.class).type();
if (type.equals(PropertyType.CATEGORY)) {
category.categories.add(buildCategory(field.getAnnotation(Property.class).description(), field.get(object)));
} else {
category.properties.add(new PropertyData(object, field, AnnotationData.getData(field), field.get(object)));
}
}
}
return category;
}
}

View File

@ -0,0 +1,129 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.config;
import java.lang.reflect.Field;
import java.util.function.Consumer;
public class PropertyData {
Object fieldClass;
Field field;
AnnotationData data;
Object defaultValue;
Consumer<?> setter;
public PropertyData(Object fieldClass, Field field, AnnotationData data, Object defaultValue) {
this.fieldClass = fieldClass;
this.field = field;
this.data = data;
this.defaultValue = defaultValue;
}
public Consumer<?> getSetter() {
return setter;
}
public void setSetter(Consumer<?> setter) {
this.setter = setter;
}
public AnnotationData getData() {
return data;
}
public Field getField() {
return field;
}
public Object getFieldClass() {
return fieldClass;
}
public String getId() {
return field.getName();
}
public boolean getBoolean() throws IllegalAccessException {
return field.getBoolean(fieldClass);
}
public void setBoolean(boolean _boolean) {
try {
field.setBoolean(fieldClass, _boolean);
} catch (Exception e) {
//Ignore
}
}
public boolean getDefaultBoolean() {
return (boolean)defaultValue;
}
public int getInt() throws IllegalAccessException {
return field.getInt(fieldClass);
}
public void setInt(int _int) {
try {
field.setInt(fieldClass, _int);
} catch (Exception e) {
//Ignore
}
}
public int getDefaultInt() {
return (int)defaultValue;
}
public double getDouble() throws IllegalAccessException {
return field.getDouble(fieldClass);
}
public void setDouble(double _double) {
try {
field.setDouble(fieldClass, _double);
} catch (Exception e) {
//Ignore
}
}
public double getDefaultDouble() {
return (double)defaultValue;
}
public String[] getStringArray() throws IllegalAccessException {
return (String[])field.get(fieldClass);
}
public void setStringArray(String[] arr)
{
try {
field.set(fieldClass, arr);
} catch (Exception e) {
//Ignore
}
}
public String[] getDefaultStringArray() {
return (String[])defaultValue;
}
}

View File

@ -0,0 +1,29 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.config;
public enum PropertyType {
INT,
DOUBLE,
BOOLEAN,
STRING_ARRAY,
CATEGORY
}

View File

@ -0,0 +1,33 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.config.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Category {
String value();
String translation() default "";
}

View File

@ -0,0 +1,32 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.config.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Config {
String value();
}

View File

@ -0,0 +1,45 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.config.annotations;
import tschipp.carryon.config.PropertyType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Property {
PropertyType type();
String description();
int min() default Integer.MIN_VALUE;
int max() default Integer.MAX_VALUE;
double minD() default Double.MIN_VALUE;
double maxD() default Double.MAX_VALUE;
String validationRegex() default ".*";
}

View File

@ -0,0 +1,29 @@
package tschipp.carryon.mixin;
import net.minecraft.client.entity.ClientAvatarEntity;
import net.minecraft.client.model.player.PlayerModel;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.entity.EntityRendererProvider.Context;
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
import net.minecraft.client.renderer.entity.player.AvatarRenderer;
import net.minecraft.client.renderer.entity.state.AvatarRenderState;
import net.minecraft.world.entity.Avatar;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import tschipp.carryon.client.render.CarryingItemRenderLayer;
@Mixin(AvatarRenderer.class)
public abstract class AvatarRendererMixin<AvatarlikeEntity extends Avatar & ClientAvatarEntity> extends LivingEntityRenderer<AvatarlikeEntity, AvatarRenderState, PlayerModel> {
public AvatarRendererMixin(Context context, PlayerModel model, float shadowRadius) {
super(context, model, shadowRadius);
}
@Inject(method = "<init>(Lnet/minecraft/client/renderer/entity/EntityRendererProvider$Context;Z)V", at = @At("RETURN"))
public void init(EntityRendererProvider.Context context, boolean slim, CallbackInfo info) {
//Player
this.addLayer(new CarryingItemRenderLayer<>(this));
}
}

View File

@ -0,0 +1,115 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.mixin;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Entity.MoveFunction;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import tschipp.carryon.Constants;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.networking.clientbound.ClientboundStartRidingPacket;
import tschipp.carryon.platform.Services;
@Mixin(Entity.class)
public abstract class EntityMixin
{
@Shadow
public boolean hasPassenger(Entity pEntity) {throw new IllegalStateException("EntityMixin application failed");}
@ModifyExpressionValue(method = "startRiding(Lnet/minecraft/world/entity/Entity;ZZ)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/EntityType;canSerialize()Z"))
private boolean onStartRidingCheck(boolean original, Entity entity, boolean force) {
if (force && entity instanceof Player) return true;
return original;
}
@Shadow public abstract void onPassengerTurned(Entity $$0);
@Inject(method = "positionRider(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/entity/Entity$MoveFunction;)V", at = @At("HEAD"), cancellable = true)
private void onPositionPassenger(Entity entity, MoveFunction move, CallbackInfo ci)
{
if((Object)this instanceof Player thisPlayer && entity instanceof Player otherPlayer)
{
if(hasPassenger(otherPlayer) && CarryOnDataManager.getCarryData(thisPlayer).isCarrying(CarryType.PLAYER))
{
Vec3 forward = new Vec3(0, 0, 0.6);
Vec3 otherPos = thisPlayer.position().add(forward.yRot((float) Math.toRadians(-thisPlayer.yBodyRot)));
otherPos = otherPos.add(0, 0.4,0);
move.accept(otherPlayer, otherPos.x, otherPos.y, otherPos.z);
((Entity)((Object)this)).onPassengerTurned(otherPlayer);
ci.cancel();
}
}
}
@Inject(method = "getDismountLocationForPassenger(Lnet/minecraft/world/entity/LivingEntity;)Lnet/minecraft/world/phys/Vec3;", at = @At("HEAD"))
private void onDismountPassenger(LivingEntity living, CallbackInfoReturnable<Vec3> cir)
{
if((Object)this instanceof Player thisPlayer && living instanceof Player otherPlayer)
{
CarryOnData carry = CarryOnDataManager.getCarryData(thisPlayer);
if(carry.isCarrying(CarryType.PLAYER))
{
carry.clear();
CarryOnDataManager.setCarryData(thisPlayer, carry);
Services.PLATFORM.sendPacketToPlayer(Constants.PACKET_ID_START_RIDING, new ClientboundStartRidingPacket(otherPlayer.getId(), false), (ServerPlayer) thisPlayer);
}
}
}
@Inject(method = "onPassengerTurned(Lnet/minecraft/world/entity/Entity;)V", at = @At("HEAD"))
private void onPassengerTurned(Entity toUpdate, CallbackInfo ci)
{
if((Object)this instanceof Player thisPlayer && toUpdate instanceof Player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(thisPlayer);
if(carry.isCarrying(CarryType.PLAYER)) {
this.clampRotation(toUpdate);
}
}
}
@Unique
private void clampRotation(Entity pEntityToUpdate) {
Entity thisEntity = (Entity)((Object)this);
pEntityToUpdate.setYBodyRot(thisEntity.getYRot());
float f = Mth.wrapDegrees(pEntityToUpdate.getYRot() - thisEntity.getYRot());
float f1 = Mth.clamp(f, -30.0F, 30.0F);
pEntityToUpdate.yRotO += f1 - f;
pEntityToUpdate.setYRot(pEntityToUpdate.getYRot() + f1 - f);
pEntityToUpdate.setYHeadRot(pEntityToUpdate.getYRot());
}
}

View File

@ -0,0 +1,36 @@
package tschipp.carryon.mixin;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.state.EntityRenderState;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import tschipp.carryon.client.render.CarryRenderHelper;
import tschipp.carryon.client.render.ICarryOnRenderState;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
@Mixin(EntityRenderer.class)
public class EntityRendererMixin {
@Inject(at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/renderer/entity/EntityRenderer;extractRenderState(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/client/renderer/entity/state/EntityRenderState;F)V",
shift = At.Shift.AFTER
), method = "createRenderState(Lnet/minecraft/world/entity/Entity;F)Lnet/minecraft/client/renderer/entity/state/EntityRenderState;")
private void onCreateRenderState(Entity entity, float $$1, CallbackInfoReturnable<EntityRenderState> cir, @Local(ordinal = 0) EntityRenderState state) {
if (entity instanceof Player player) {
CarryOnData carry = CarryOnDataManager.getCarryData(player);
ICarryOnRenderState carryOnRenderState = (ICarryOnRenderState) state;
carryOnRenderState.setCarryOnData(carry);
carryOnRenderState.setRenderWidth(CarryRenderHelper.getRenderWidth(player));
carryOnRenderState.setPlayer(player);
}
}
}

View File

@ -0,0 +1,96 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.mixin;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.renderer.entity.state.HumanoidRenderState;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import tschipp.carryon.Constants;
import tschipp.carryon.client.render.ICarryOnRenderState;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptRender;
@Mixin(HumanoidModel.class)
public class HumanoidModelMixin {
@Shadow
public ModelPart rightArm;
@Shadow
public ModelPart leftArm;
@Inject(at = @At("RETURN"), method = "setupAnim(Lnet/minecraft/client/renderer/entity/state/HumanoidRenderState;)V")
private void onSetupAnimations(HumanoidRenderState state, CallbackInfo ci)
{
if(state instanceof ICarryOnRenderState carryOnRenderState && Constants.CLIENT_CONFIG.renderArms)
{
CarryOnData carry = carryOnRenderState.getCarryOnData();
if(carry != null && carry.isCarrying() && !state.isVisuallySwimming && !state.isFallFlying)
{
boolean sneaking = state.isCrouching;
float x = 1.0f + (sneaking ? 0.2f : 0.0f) + (carry.isCarrying(CarryOnData.CarryType.BLOCK) ? 0.0f : 0.3f);
float z = 0.05f;
float width = carryOnRenderState.getRenderWidth();
float offset = Math.min((width - 1) / 1.5f, 0.2f);
if(carry.getActiveScript().isPresent())
{
ScriptRender render = carry.getActiveScript().get().scriptRender();
boolean renderLeft = render.renderLeftArm();
boolean renderRight = render.renderRightArm();
Vec3 rotLeft = render.renderRotationLeftArm().getVec(-x, -offset, z);
Vec3 rotRight = render.renderRotationRightArm().getVec(-x, offset, -z);
if(renderLeft)
changeRotation(leftArm, (float) rotLeft.x, (float) rotLeft.y, (float) rotLeft.z);
if(renderRight)
changeRotation(rightArm, (float) rotRight.x, (float) rotRight.y, (float) rotRight.z);
}
else {
changeRotation(rightArm, -x, offset, -z);
changeRotation(leftArm, -x, -offset, z);
}
}
}
}
@Unique
private void changeRotation(ModelPart part, float x, float y, float z)
{
part.xRot = x;
part.yRot = y;
part.zRot = z;
}
}

View File

@ -0,0 +1,86 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.mixin;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.core.NonNullList;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Blocks;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
@Mixin(Inventory.class)
public class InventoryMixin
{
@Unique
private static final ItemStack DUMMY_STACK = new ItemStack(Blocks.COBBLESTONE, 1);
@Shadow
public Player player;
@Shadow
public int selected;
@Shadow
public NonNullList<ItemStack> items;
@WrapOperation(method = "getFreeSlot()I", at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/core/NonNullList;get(I)Ljava/lang/Object;"))
private Object getFreeSlotEmptyCheck(NonNullList<Object> instance, int slot, Operation<Object> original)
{
if(slot == selected && CarryOnDataManager.getCarryData(player).isCarrying())
{
return DUMMY_STACK;
}
else
return original.call(instance, slot);
}
@Inject(method = "addAndPickItem(Lnet/minecraft/world/item/ItemStack;)V", at = @At("HEAD"), cancellable = true)
private void onPickBlock(CallbackInfo info)
{
if(CarryOnDataManager.getCarryData(player).isCarrying())
info.cancel();
}
@Inject(method = "pickSlot(I)V", at = @At("HEAD"), cancellable = true)
private void onPickSlot(int slot, CallbackInfo info)
{
if(CarryOnDataManager.getCarryData(player).isCarrying())
info.cancel();
}
@Inject(method = "setSelectedSlot(I)V", at = @At("HEAD"), cancellable = true)
private void onSwapPaint(int slot, CallbackInfo info)
{
CarryOnData data = CarryOnDataManager.getCarryData(player);
if(data.isCarrying() && data.getSelected() != slot)
info.cancel();
}
}

View File

@ -0,0 +1,51 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.mixin;
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.player.Inventory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import tschipp.carryon.common.carry.CarryOnDataManager;
@Mixin(Minecraft.class)
public class MinecraftMixin {
@WrapWithCondition(
method = "handleKeybinds()V",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/player/Inventory;setSelectedSlot(I)V",
ordinal = 0
)
)
private boolean allowSlotSelection(Inventory inv, int slot) {
boolean carrying = CarryOnDataManager.getCarryData(inv.player).isCarrying();
// Allow if not carrying
if (!carrying) return true;
// Block only if trying to switch away
return inv.getSelectedSlot() == slot;
}
}

View File

@ -0,0 +1,68 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.mixin;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.storage.ValueInput;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.carry.CarryOnDataManager;
import java.util.Optional;
@Mixin(Player.class)
public abstract class PlayerMixin extends LivingEntity {
private PlayerMixin(EntityType<? extends LivingEntity> type, Level level) {
super(type, level);
}
//We leave this in here to ensure cross-compatibility if world are upgraded from <1.21.8. Should be removed in the future.
@Inject(method = "readAdditionalSaveData(Lnet/minecraft/world/level/storage/ValueInput;)V", at = @At("RETURN"))
private void onReadAdditionalSaveData(ValueInput input, CallbackInfo ci)
{
Optional<CarryOnData> res = input.read("CarryOnData", CarryOnData.CODEC);
res.ifPresent(data -> CarryOnDataManager.setCarryData((Player)((Object)this), data));
}
@Override
public void stopRiding() {
Entity entity = this.getVehicle();
if (entity instanceof Player && entity.getPassengers().size() < 2){
CarryOnData carry = CarryOnDataManager.getCarryData((Player) entity);
if (carry.getType() == CarryType.PLAYER){
carry.clear();
((Player) entity).removeEffect(MobEffects.SLOWNESS);
}
}
super.stopRiding();
}
}

View File

@ -0,0 +1,56 @@
package tschipp.carryon.mixin;
import net.minecraft.client.renderer.entity.state.HumanoidRenderState;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import tschipp.carryon.client.render.ICarryOnRenderState;
import tschipp.carryon.common.carry.CarryOnData;
@Mixin(HumanoidRenderState.class)
public class PlayerRenderStateMixin implements ICarryOnRenderState {
@Unique
public CarryOnData carryOnData = null;
@Unique
public float renderWidth = 0f;
@Unique
public Player player = null;
@Unique
@Override
public CarryOnData getCarryOnData() {
return carryOnData;
}
@Unique
@Override
public void setCarryOnData(CarryOnData data) {
carryOnData = data;
}
@Unique
@Override
public float getRenderWidth() {
return renderWidth;
}
@Unique
@Override
public void setRenderWidth(float val) {
renderWidth = val;
}
@Override
public Player getPlayer() {
return player;
}
@Override
public void setPlayer(Player player) {
this.player = player;
}
}

View File

@ -0,0 +1,29 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.networking;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.world.entity.player.Player;
public interface PacketBase extends CustomPacketPayload {
void handle(Player player);
}

View File

@ -0,0 +1,59 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.networking.clientbound;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.Constants;
import tschipp.carryon.networking.PacketBase;
public record ClientboundStartRidingOtherPlayerPacket(int mount, int rider, boolean ride) implements PacketBase
{
public static final StreamCodec<RegistryFriendlyByteBuf, ClientboundStartRidingOtherPlayerPacket> CODEC = StreamCodec.composite(
ByteBufCodecs.INT, ClientboundStartRidingOtherPlayerPacket::mount,
ByteBufCodecs.INT, ClientboundStartRidingOtherPlayerPacket::rider,
ByteBufCodecs.BOOL, ClientboundStartRidingOtherPlayerPacket::ride,
ClientboundStartRidingOtherPlayerPacket::new
);
public static final Type<ClientboundStartRidingOtherPlayerPacket> TYPE = new Type<>(Constants.PACKET_ID_START_RIDING_OTHER);
@Override
public void handle(Player player)
{
Entity mount = player.level().getEntity(this.mount);
Entity rider = player.level().getEntity(this.rider);
if(mount != null && rider != null)
if(ride)
rider.startRiding(mount, true,true);
else
rider.stopRiding();
}
@Override
public Type<ClientboundStartRidingOtherPlayerPacket> type() {
return TYPE;
}
}

View File

@ -0,0 +1,57 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.networking.clientbound;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.Constants;
import tschipp.carryon.networking.PacketBase;
public record ClientboundStartRidingPacket(int iden, boolean ride) implements PacketBase
{
public static final StreamCodec<RegistryFriendlyByteBuf, ClientboundStartRidingPacket> CODEC = StreamCodec.composite(
ByteBufCodecs.INT, ClientboundStartRidingPacket::iden,
ByteBufCodecs.BOOL, ClientboundStartRidingPacket::ride,
ClientboundStartRidingPacket::new
);
public static final CustomPacketPayload.Type<ClientboundStartRidingPacket> TYPE = new Type<>(Constants.PACKET_ID_START_RIDING);
@Override
public void handle(Player player)
{
Entity otherPlayer = player.level().getEntity(this.iden);
if(otherPlayer != null)
if(ride)
otherPlayer.startRiding(player);
else
otherPlayer.stopRiding();
}
@Override
public Type<ClientboundStartRidingPacket> type() {
return TYPE;
}
}

View File

@ -0,0 +1,61 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.networking.clientbound;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.Constants;
import tschipp.carryon.common.scripting.CarryOnScript;
import tschipp.carryon.common.scripting.ScriptManager;
import tschipp.carryon.networking.PacketBase;
import java.util.List;
public record ClientboundSyncScriptsPacket(Tag serialized) implements PacketBase
{
public static final StreamCodec<RegistryFriendlyByteBuf, ClientboundSyncScriptsPacket> CODEC = StreamCodec.composite(
ByteBufCodecs.TAG, ClientboundSyncScriptsPacket::serialized,
ClientboundSyncScriptsPacket::new
);
public static final CustomPacketPayload.Type<ClientboundSyncScriptsPacket> TYPE = new Type<>(Constants.PACKET_ID_SYNC_SCRIPTS);
@Override
public void handle(Player player)
{
DataResult<List<CarryOnScript>> res = Codec.list(CarryOnScript.CODEC).parse(NbtOps.INSTANCE, serialized);
List<CarryOnScript> scripts = res.getOrThrow((s) -> {throw new RuntimeException("Failed deserializing carry on scripts on the client: " + s);});
ScriptManager.SCRIPTS.clear();
ScriptManager.SCRIPTS.addAll(scripts);
}
@Override
public Type<ClientboundSyncScriptsPacket> type() {
return TYPE;
}
}

View File

@ -0,0 +1,54 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.networking.serverbound;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.Constants;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.networking.PacketBase;
public record ServerboundCarryKeyPressedPacket(boolean pressed) implements PacketBase
{
public static final StreamCodec<RegistryFriendlyByteBuf, ServerboundCarryKeyPressedPacket> CODEC = StreamCodec.composite(
ByteBufCodecs.BOOL, ServerboundCarryKeyPressedPacket::pressed,
ServerboundCarryKeyPressedPacket::new
);
public static final CustomPacketPayload.Type<ServerboundCarryKeyPressedPacket> TYPE = new Type<>(Constants.PACKET_ID_KEY_PRESSED);
@Override
public void handle(Player player)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
carry.setKeyPressed(this.pressed);
CarryOnDataManager.setCarryData(player, carry);
}
@Override
public Type<ServerboundCarryKeyPressedPacket> type() {
return TYPE;
}
}

View File

@ -0,0 +1,43 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.platform;
import tschipp.carryon.Constants;
import tschipp.carryon.platform.services.IGamestagePlatformHelper;
import tschipp.carryon.platform.services.IPlatformHelper;
import java.util.ServiceLoader;
public class Services {
public static final IPlatformHelper PLATFORM = load(IPlatformHelper.class);
public static final IGamestagePlatformHelper GAMESTAGES = load(IGamestagePlatformHelper.class);
public static <T> T load(Class<T> clazz) {
final T loadedService = ServiceLoader.load(clazz)
.findFirst()
.orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName()));
Constants.LOG.debug("Loaded {} for service {}", loadedService, clazz);
return loadedService;
}
}

View File

@ -0,0 +1,28 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.platform.services;
import net.minecraft.world.entity.player.Player;
public interface IGamestagePlatformHelper
{
boolean hasStage(Player player, String stage);
}

View File

@ -0,0 +1,79 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.platform.services;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.Identifier;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.config.BuiltConfig;
import tschipp.carryon.networking.PacketBase;
import java.util.function.BiConsumer;
public interface IPlatformHelper {
/**
* Gets the name of the current platform
*
* @return The name of the current platform.
*/
String getPlatformName();
/**
* Checks if a mod with the given id is loaded.
*
* @param modId The mod to check if it is loaded.
* @return True if the mod is loaded, false otherwise.
*/
boolean isModLoaded(String modId);
/**
* Check if the game is currently in a development environment.
*
* @return True if in a development environment, false otherwise.
*/
boolean isDevelopmentEnvironment();
void registerConfig(BuiltConfig cfg);
<T extends PacketBase, B extends FriendlyByteBuf> void registerServerboundPacket(CustomPacketPayload.Type<T> type, Class<T> clazz, StreamCodec<B, T> codec, BiConsumer<T, Player> handler, Object... args);
<T extends PacketBase, B extends FriendlyByteBuf> void registerClientboundPacket(CustomPacketPayload.Type<T> type, Class<T> clazz, StreamCodec<B, T> codec, BiConsumer<T, Player> handler, Object... args);
void sendPacketToServer(Identifier id, PacketBase packet);
void sendPacketToPlayer(Identifier id, PacketBase packet, ServerPlayer player);
default void sendPacketToAllPlayers(Identifier id, PacketBase packet, ServerLevel level) {
for(ServerPlayer p : level.players())
sendPacketToPlayer(id, packet, p);
}
CarryOnData getCarryData(Player player);
void setCarryData(Player player, CarryOnData data);
}

View File

@ -0,0 +1,38 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.utils;
public class StringHelper
{
public static boolean matchesWildcards(String str, String[] wildcards)
{
for(String w : wildcards)
{
if(!str.contains(w))
return false;
int i = str.indexOf(w);
str = str.substring(i + w.length());
}
return true;
}
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "Einstellungen",
"carryon.category.blacklist": "Blacklist",
"carryon.category.modeloverrides": "Modellüberschreibungen (Fortgeschritten)",
"carryon.category.custompickupconditions": "Benutzerdefinierte Bedingungen (Fortgeschritten)",
"carryon.category.whitelist": "Whitelist",
"carryon.general.modeloverrides.modeloverrides": "Modellüberschreibungen",
"carryon.general.blacklist.forbiddenentities": "Entitäten, die Spieler nicht aufheben dürfen",
"carryon.general.blacklist.forbiddentiles": "Blöcke, die Spieler nicht aufheben dürfen",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Benutzerdefinierte Bedingungen für Blöcke",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Benutzerdefinierte Bedingungen für Entitäten",
"key.carry.desc": "Carry",
"key.category.carryon.key.carry.category": "Carry On"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "sᵷuᴉʇʇǝS",
"carryon.category.blacklist": "ʇsᴉꞁʞɔɐꞁᗺ",
"carryon.category.modeloverrides": "(pǝɔuɐʌpⱯ) sǝpᴉɹɹǝʌO ꞁǝpoW",
"carryon.category.custompickupconditions": "(pǝɔuɐʌpⱯ) suoᴉʇᴉpuoƆ dnʞɔᴉԀ ɯoʇsnƆ",
"carryon.category.whitelist": "ʇsᴉꞁǝʇᴉɥM",
"carryon.general.modeloverrides.modeloverrides": "sǝpᴉɹɹǝʌO ꞁǝpoW",
"carryon.general.blacklist.forbiddenentities": "dn ʞɔᴉd ʇouuɐɔ ɹǝʎɐꞁԀ ǝɥʇ ʇɐɥʇ sǝᴉʇᴉʇuƎ",
"carryon.general.blacklist.forbiddentiles": "dn ʞɔᴉd ʇouuɐɔ ɹǝʎɐꞁԀ ǝɥʇ ʇɐɥʇ sʞɔoꞁᗺ",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "suoᴉʇᴉpuoƆ dnʞɔᴉԀ ʞɔoꞁᗺ ɯoʇsnƆ",
"carryon.category.custompickupconditions.custompickupconditionsentities": "suoᴉʇᴉpuoƆ dnʞɔᴉԀ ʎʇᴉʇuƎ ɯoʇsnƆ",
"key.carry.desc": "ʎɹɹɐƆ",
"key.category.carryon.key.carry.category": "uO ʎɹɹɐƆ"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "Settings",
"carryon.category.blacklist": "Blacklist",
"carryon.category.modeloverrides": "Model Overrides (Advanced)",
"carryon.category.custompickupconditions": "Custom Pickup Conditions (Advanced)",
"carryon.category.whitelist": "Whitelist",
"carryon.general.modeloverrides.modeloverrides": "Model Overrides",
"carryon.general.blacklist.forbiddenentities": "Entities that the Player cannot pick up",
"carryon.general.blacklist.forbiddentiles": "Blocks that the Player cannot pick up",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Custom Block Pickup Conditions",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Custom Entity Pickup Conditions",
"key.carry.desc": "Carry",
"key.category.carryon.key.carry.category": "Carry On"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "Configuraciones",
"carryon.category.blacklist": "Lista Negra",
"carryon.category.modeloverrides": "Reemplazos de Modelos (Avanzado)",
"carryon.category.custompickupconditions": "Condiciones Personalizadas de Recogida (Avanzado)",
"carryon.category.whitelist": "Lista Blanca",
"carryon.general.modeloverrides.modeloverrides": "Reemplazos de Modelos",
"carryon.general.blacklist.forbiddenentities": "Entidades que el jugador no puede levantar",
"carryon.general.blacklist.forbiddentiles": "Bloques que el jugador no puede levantar",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Condiciones Personalizadas de Recogida de Bloques",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Condiciones Personalizadas de Recogida de Entidades",
"key.carry.desc": "Cargar",
"key.category.carryon.key.carry.category": "Carry On"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "Ajustes",
"carryon.category.blacklist": "Lista Negra",
"carryon.category.modeloverrides": "Reemplazos de Modelo (Avanzado)",
"carryon.category.custompickupconditions": "Condiciones Personalizadas para Recoger (Avanzado)",
"carryon.category.whitelist": "Lista Blanca",
"carryon.general.modeloverrides.modeloverrides": "Reemplazos de Modelo",
"carryon.general.blacklist.forbiddenentities": "Entidades que el jugador no puede recoger",
"carryon.general.blacklist.forbiddentiles": "Bloques que el jugador no puede recoger",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Condiciones Personalizadas para Recoger Bloques",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Condiciones Personalizadas para Recoger Entidades",
"key.carry.desc": "Recoger",
"key.category.carryon.key.carry.category": "Carry On"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "Configuración",
"carryon.category.blacklist": "Lista negra",
"carryon.category.modeloverrides": "Reescribir modelo (Avanzado)",
"carryon.category.custompickupconditions": "Customizar condiciones de recoger (Avanzado)",
"carryon.category.whitelist": "Lista blanca",
"carryon.general.modeloverrides.modeloverrides": "Reescribir modelo",
"carryon.general.blacklist.forbiddenentities": "Entidades que el jugador no puede recoger",
"carryon.general.blacklist.forbiddentiles": "Bloques que el jugador no puede recoger",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Customizar condiciones para recoger bloques",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Customizar condiciones para recoger entidades",
"key.carry.desc": "Agarrar",
"key.category.carryon.key.carry.category": "Carry On"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "Paramètres",
"carryon.category.blacklist": "Liste noire",
"carryon.category.modeloverrides": "Modèle de Remplacement (Avancé)",
"carryon.category.custompickupconditions": "Conditions de ramassage personalisés (Avancé)",
"carryon.category.whitelist": "Liste blanche",
"carryon.general.modeloverrides.modeloverrides": "Modèle de Remplacement",
"carryon.general.blacklist.forbiddenentities": "Entités que le joueur ne peut pas saisir",
"carryon.general.blacklist.forbiddentiles": "Blocs que le joueur ne peut pas saisir",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Conditions de ramassage de blocs personalisés",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Conditions de ramassage d'entités personalisés",
"key.carry.desc": "Saisir",
"key.category.carryon.key.carry.category": "Carry On"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "Beállítások",
"carryon.category.blacklist": "Feketelista",
"carryon.category.modeloverrides": "Model felülírások (Fejlett)",
"carryon.category.custompickupconditions": "Egyedi felvételi feltételek (Fejlett)",
"carryon.category.whitelist": "Fehérlista",
"carryon.general.modeloverrides.modeloverrides": "Model felülírások",
"carryon.general.blacklist.forbiddenentities": "Entitások amiket a játékos nem vehet fel",
"carryon.general.blacklist.forbiddentiles": "Blokkok amiket a játékos nem vehet fel",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Egyedi blokk felvételi feltételek",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Egyedi entitás felvételi feltételek",
"key.carry.desc": "Cipelés",
"key.category.carryon.key.carry.category": "Carry On"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "Inpostazioni",
"carryon.category.blacklist": "Blacklist",
"carryon.category.modeloverrides": "Sostituzioni modello (avanzate)",
"carryon.category.custompickupconditions": "Condizioni di prelievo personalizzate (avanzate)",
"carryon.category.whitelist": "Whitelist",
"carryon.general.modeloverrides.modeloverrides": "Sostituzioni modello",
"carryon.general.blacklist.forbiddenentities": "Entità che il giocatore non può raccogliere",
"carryon.general.blacklist.forbiddentiles": "Blocchi che il giocatore non può raccogliere",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Condizioni di prelievo blocco personalizzate",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Condizioni di prelievo entità personalizzate",
"key.carry.desc": "Afferra",
"key.category.carryon.key.carry.category": "Carry On Mod"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "設定",
"carryon.category.blacklist": "ブラックリスト",
"carryon.category.modeloverrides": "モデルの上書き(上級)",
"carryon.category.custompickupconditions": "カスタム持ち上げ条件(上級)",
"carryon.category.whitelist": "ホワイトリスト",
"carryon.general.modeloverrides.modeloverrides": "モデルの上書き",
"carryon.general.blacklist.forbiddenentities": "プレイヤーが持ち上げられないエンティティ",
"carryon.general.blacklist.forbiddentiles": "プレーヤーが持ち上げられないブロック",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "カスタムブロック持ち上げ条件",
"carryon.category.custompickupconditions.custompickupconditionsentities": "カスタムエンティティ持ち上げ条件",
"key.carry.desc": "Carry",
"key.category.carryon.key.carry.category": "Carry On"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "설정",
"carryon.category.blacklist": "블랙리스트",
"carryon.category.modeloverrides": "모델 재정의 (고급)",
"carryon.category.custompickupconditions": "맞춤형 들기 조건 (고급)",
"carryon.category.whitelist": "화이트리스트",
"carryon.general.modeloverrides.modeloverrides": "모델 재정의",
"carryon.general.blacklist.forbiddenentities": "플레이어가 들 수 없는 개체",
"carryon.general.blacklist.forbiddentiles": "플레이어가 들 수 없는 블록",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "맞춤형 블록 들기 조건",
"carryon.category.custompickupconditions.custompickupconditionsentities": "맞춤형 개체 들기 조건",
"key.carry.desc": "들고 나르기",
"key.category.carryon.key.carry.category": "Carry On"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "Настройки",
"carryon.category.blacklist": "Чёрный список",
"carryon.category.modeloverrides": "Переопределения модели (Улучшенное)",
"carryon.category.custompickupconditions": "Индивидуальные условия поднятия (Улучшенное)",
"carryon.category.whitelist": "Белый список",
"carryon.general.modeloverrides.modeloverrides": "Переопределения модели",
"carryon.general.blacklist.forbiddenentities": "Сущности, которых игрок не может поднять",
"carryon.general.blacklist.forbiddentiles": "Блоки, которые игрок не может поднять",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Пользовательские условия поднятия блока",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Пользовательские условия поднятия сущности",
"key.carry.desc": "Поднять",
"key.category.carryon.key.carry.category": "Carry On"
}

View File

@ -0,0 +1,17 @@
{
"__comment__": "Translated by @alpeerkaraca",
"carryon.category.settings": "Ayarlar",
"carryon.category.blacklist": "Kara Liste",
"carryon.category.modeloverrides": "Üzerine Yazılan Modeller (Gelişmiş)",
"carryon.category.custompickupconditions": "Özel Yerden Alma Durumları (Gelişmiş)",
"carryon.category.whitelist": "Beyaz Liste",
"carryon.general.modeloverrides.modeloverrides": "Modellerin Üzerine Yaz",
"carryon.general.blacklist.forbiddenentities": "Oyuncunun Alamayacağı Varlıklar",
"carryon.general.blacklist.forbiddentiles": "Oyuncunun Alamayacağı Bloklar",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Özel Blok Alma Durumları",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Özel Varlık Alma Durumları",
"key.carry.desc": "Taşı",
"key.category.carryon.key.carry.category": "Carry On"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "Налаштування",
"carryon.category.blacklist": "Чорний список",
"carryon.category.modeloverrides": "Перевизначення моделей (Розширені)",
"carryon.category.custompickupconditions": "Користувацькі умови підбору (Розширені)",
"carryon.category.whitelist": "Білий список",
"carryon.general.modeloverrides.modeloverrides": "Перевизначення моделей",
"carryon.general.blacklist.forbiddenentities": "Сутності, які гравець не може підібрати",
"carryon.general.blacklist.forbiddentiles": "Блоки, які гравець не може підібрати",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Користувацькі умови підбору блоків",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Користувацькі умови підбору сутностей",
"key.carry.desc": "Нести",
"key.category.carryon.key.carry.category": "Carry On"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "设置",
"carryon.category.blacklist": "黑名单",
"carryon.category.modeloverrides": "模型覆盖(高级设置)",
"carryon.category.custompickupconditions": "自定义抱起条件(高级设置)",
"carryon.category.whitelist": "白名单",
"carryon.general.modeloverrides.modeloverrides": "模型覆盖",
"carryon.general.blacklist.forbiddenentities": "玩家不能抱起的实体",
"carryon.general.blacklist.forbiddentiles": "玩家不能抱起的方块",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "自定义抱起方块条件",
"carryon.category.custompickupconditions.custompickupconditionsentities": "自定义抱起实体条件",
"key.carry.desc": "抱起",
"key.category.carryon.key.carry.category": "搬运"
}

View File

@ -0,0 +1,16 @@
{
"carryon.category.settings": "設定",
"carryon.category.blacklist": "黑名單",
"carryon.category.modeloverrides": "模型覆蓋(進階)",
"carryon.category.custompickupconditions": "自訂拾取條件(進階)",
"carryon.category.whitelist": "白名單",
"carryon.general.modeloverrides.modeloverrides": "模型覆蓋",
"carryon.general.blacklist.forbiddenentities": "玩家無法拾取的實體",
"carryon.general.blacklist.forbiddentiles": "玩家無法拾取的方塊",
"carryon.category.custompickupconditions.custompickupconditionsblocks": "自訂方塊拾取條件",
"carryon.category.custompickupconditions.custompickupconditionsentities": "自訂實體拾取條件",
"key.carry.desc": "攜帶",
"key.category.carryon.key.carry.category": "Carry On"
}

View File

@ -0,0 +1,25 @@
{
"required": true,
"minVersion": "0.8",
"package": "tschipp.carryon.mixin",
"compatibilityLevel": "JAVA_21",
"mixins": [
"EntityMixin",
"InventoryMixin",
"PlayerMixin"
],
"client": [
"AvatarRendererMixin",
"EntityRendererMixin",
"HumanoidModelMixin",
"MinecraftMixin",
"PlayerRenderStateMixin"
],
"server": [
],
"plugin": "tschipp.carryon.mixin.CarryOnMixinConfigPlugin",
"injectors": {
"defaultRequire": 1
},
"refmap": "${mod_id}.refmap.json"
}

View File

@ -0,0 +1,5 @@
{
"replace": false,
"values": [
]
}

View File

@ -0,0 +1,5 @@
{
"replace": false,
"values": [
]
}

View File

@ -0,0 +1,5 @@
{
"replace": false,
"values": [
]
}

View File

@ -0,0 +1,5 @@
{
"replace": false,
"values": [
]
}

View File

@ -0,0 +1,5 @@
{
"replace": false,
"values": [
]
}

View File

@ -0,0 +1,5 @@
{
"replace": false,
"values": [
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

View File

@ -0,0 +1,6 @@
{
"pack": {
"description": "${mod_name}",
"pack_format": 34
}
}

60
Fabric/build.gradle Normal file
View File

@ -0,0 +1,60 @@
plugins {
id 'multiloader-loader'
id 'fabric-loom' version "${loom_version}"
}
repositories {
maven {
name = "Shedaniel"
url "https://maven.shedaniel.me/"
}
maven { url 'https://jitpack.io' }
maven {
name = "Terraformers"
url = "https://maven.terraformersmc.com/"
}
}
dependencies {
minecraft "com.mojang:minecraft:${minecraft_version}"
mappings loom.layered() {
officialMojangMappings()
parchment("org.parchmentmc.data:parchment-${parchment_mappings_fabric}@zip")
}
modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}"
implementation group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.1'
modApi("me.shedaniel.cloth:cloth-config-fabric:${cloth_config_version}") {
exclude(group: "net.fabricmc.fabric-api")
}
modApi "com.terraformersmc:modmenu:17.0.0-beta.1"
}
loom {
def aw = project(':Common').file("src/main/resources/${mod_id}.accesswidener")
if (aw.exists()) {
accessWidenerPath.set(aw)
}
mixin {
defaultRefmapName.set("${mod_id}.refmap.json")
}
runs {
client {
client()
setConfigName("Fabric Client")
ideConfigGenerated(true)
runDir("run")
}
server {
server()
setConfigName("Fabric Server")
ideConfigGenerated(true)
runDir("run")
}
}
}

View File

@ -0,0 +1,57 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.client.keybinds.CarryOnKeybinds;
import tschipp.carryon.events.ClientEvents;
import tschipp.carryon.networking.PacketBase;
import java.util.function.BiConsumer;
public class CarryOnFabricClientMod implements ClientModInitializer
{
@Override
public void onInitializeClient()
{
CarryOnKeybinds.registerKeybinds(KeyBindingHelper::registerKeyBinding);
ClientEvents.registerEvents();
CarryOnCommon.registerClientPackets(true);
}
public static void sendPacketToServer(PacketBase packet)
{
ClientPlayNetworking.send(packet);
}
public static <T extends PacketBase> void registerClientboundPacket(CustomPacketPayload.Type<T> id, BiConsumer<T, Player> handler)
{
ClientPlayNetworking.registerGlobalReceiver(id, (T packet, ClientPlayNetworking.Context context) -> {
context.client().execute(() -> {
handler.accept(packet, context.player());
});
});
}
}

View File

@ -0,0 +1,74 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.attachment.v1.AttachmentRegistry;
import net.fabricmc.fabric.api.attachment.v1.AttachmentType;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.Identifier;
import net.minecraft.server.level.ServerPlayer;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.config.fabric.ConfigLoaderImpl;
import tschipp.carryon.events.CommonEvents;
import java.io.IOException;
public class CarryOnFabricMod implements ModInitializer {
public static final AttachmentType<CarryOnData> CARRY_ON_DATA_ATTACHMENT_TYPE = AttachmentRegistry.create(
Identifier.fromNamespaceAndPath(Constants.MOD_ID, "carry_on_data"),
builder -> builder
.initializer(() -> new CarryOnData(new CompoundTag()))
.persistent(CarryOnData.CODEC)
.syncWith(CarryOnData.STREAM_CODEC, (t, p) ->{
ServerPlayer player = (ServerPlayer) t;
// the isAlive check avoids us syncing attachment data about dead players. Which causes a disconnect
// player.tickCount > 0 avoids us syncing attachment data about players the instant they spawn.
// Which also causes a disconnect as the player entity may not be synced yet.
return p.connection != null && player.isAlive() && !p.isRemoved() && player.tickCount > 0;
})
);
@Override
public void onInitialize() {
// This method is invoked by the Fabric mod loader when it is ready
// to load your mod. You can access Fabric and Common code in this
// project.
CarryOnCommon.registerConfig();
try {
ConfigLoaderImpl.initialize();
} catch (IOException e) {
throw new RuntimeException(e);
}
CommonEvents.registerEvents();
CarryOnCommon.registerServerPackets();
CarryOnCommon.registerClientPackets(false);
}
}

View File

@ -0,0 +1,86 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.compat;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import tschipp.carryon.Constants;
import tschipp.carryon.platform.Services;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ArchitecturyCompat {
private static Object INVOKER_INSTANCE;
private static Method PLACE_BLOCK;
private static Method IS_FALSE;
@SuppressWarnings("unchecked")
private static void setup( ) {
try {
Class BlockEvent = Class.forName("dev.architectury.event.events.common.BlockEvent");
Field PLACE = BlockEvent.getField("PLACE");
Method invoker = Class.forName("dev.architectury.event.Event").getMethod("invoker");
INVOKER_INSTANCE = invoker.invoke(PLACE.get(BlockEvent));
Class PlaceClass = Class.forName("dev.architectury.event.events.common.BlockEvent$Place");
PLACE_BLOCK = PlaceClass.getMethod("placeBlock", Level.class, BlockPos.class, BlockState.class, Entity.class);
Class EventResult = Class.forName("dev.architectury.event.EventResult");
IS_FALSE = EventResult.getMethod("isFalse");
} catch (Exception e) {
Constants.LOG.warn("Error while initializing Architectury Compat: " + e);
}
}
public static boolean active() {
return Services.PLATFORM.isModLoaded("architectury");
}
public static boolean sendPlaceEvent(Level level, BlockPos pos, BlockState state, Player player) {
if(!active())
return true;
if(INVOKER_INSTANCE == null || PLACE_BLOCK == null)
setup();
if(INVOKER_INSTANCE != null && PLACE_BLOCK != null && IS_FALSE != null) {
try {
Object eventResult = PLACE_BLOCK.invoke(INVOKER_INSTANCE, level, pos, state, player);
boolean canceled = (boolean) IS_FALSE.invoke(eventResult);
return !canceled;
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
return true;
}
}

View File

@ -0,0 +1,16 @@
package tschipp.carryon.compat;
import net.minecraft.client.gui.screens.Screen;
import tschipp.carryon.config.BuiltConfig;
import tschipp.carryon.config.fabric.ConfigLoaderImpl;
public class ClothConfigCompatFabric {
public static Screen createScreen(BuiltConfig client, BuiltConfig common, Screen screen) {
return ClothConfigCompat.getConfigScreen(client, common, screen, ConfigLoaderImpl::saveConfigs);
}
}

View File

@ -0,0 +1,17 @@
package tschipp.carryon.compat;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import tschipp.carryon.config.BuiltConfig;
import tschipp.carryon.config.fabric.ConfigLoaderImpl;
public class ModMenuCompat implements ModMenuApi {
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
BuiltConfig[] configs = ConfigLoaderImpl.CONFIGS.values().toArray(new BuiltConfig[0]);
return (parent) -> ClothConfigCompatFabric.createScreen(configs[1], configs[0], parent);
}
}

View File

@ -0,0 +1,188 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.config.fabric;
import com.google.gson.*;
import net.fabricmc.loader.api.FabricLoader;
import org.apache.commons.io.FileUtils;
import tschipp.carryon.common.config.ListHandler;
import tschipp.carryon.config.*;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class ConfigLoaderImpl {
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
//Default JSON and config data.
public static final Map<JsonObject, BuiltConfig> CONFIGS = new LinkedHashMap<>();
public static void initialize() throws IOException {
Path cfgPath = FabricLoader.getInstance().getConfigDir();
for (Map.Entry<JsonObject, BuiltConfig> entry : CONFIGS.entrySet()) {
File cfgFile = new File(cfgPath.toFile(), entry.getValue().fileName+".json");
if (!cfgFile.exists()) {
cfgPath.toFile().mkdirs();
FileUtils.write(cfgFile, GSON.toJson(entry.getKey()), StandardCharsets.UTF_8);
} else {
JsonObject cfgJson = GSON.fromJson(FileUtils.readFileToString(cfgFile, StandardCharsets.UTF_8), JsonObject.class);
if(cfgJson == null)
{
cfgPath.toFile().mkdirs();
FileUtils.write(cfgFile, GSON.toJson(entry.getKey()), StandardCharsets.UTF_8);
}
FileUtils.write(cfgFile, GSON.toJson(loadConfig(entry.getValue(), cfgJson)), StandardCharsets.UTF_8);
}
}
}
private static JsonObject loadConfig(BuiltCategory category, JsonObject config) {
config.entrySet().forEach((entry) -> {
String id = entry.getKey();
if (!id.startsWith("//")) {
JsonElement value = entry.getValue();
if (value instanceof JsonPrimitive configValue) {
category.getProperty(id).ifPresent(data -> {
if (configValue.isBoolean() && data.getData().type().equals(PropertyType.BOOLEAN))
data.setBoolean(configValue.getAsBoolean());
if (configValue.isNumber() && data.getData().type().equals(PropertyType.INT)) {
int configInt = configValue.getAsInt();
if (configInt > data.getData().max() || configInt < data.getData().min()) {
try {
config.addProperty(id, data.getInt());
} catch (IllegalAccessException ignored) {
}
} else {
data.setInt(configInt);
}
}
if (configValue.isNumber() && data.getData().type().equals(PropertyType.DOUBLE)) {
double configDouble = configValue.getAsDouble();
if (configDouble > data.getData().maxD() || configDouble < data.getData().minD()) {
try {
config.addProperty(id, data.getDouble());
} catch (IllegalAccessException ignored) {
}
} else {
data.setDouble(configDouble);
}
}
});
} else if (value instanceof JsonObject subConfig) {
category.getCategory(id).ifPresent(cat -> loadConfig(cat, subConfig));
} else if (value instanceof JsonArray list) {
category.getProperty(id).ifPresent(data -> {
if(data.getData().type() == PropertyType.STRING_ARRAY)
{
List<String> ls = new ArrayList<>();
for(JsonElement arrEle : list)
{
if(arrEle instanceof JsonPrimitive p && p.isString())
{
ls.add(p.getAsString());
}
}
data.setStringArray(ls.toArray(new String[ls.size()]));
}
});
}
}
});
return config;
}
public static void saveConfigs() {
try {
Path cfgPath = FabricLoader.getInstance().getConfigDir();
for (Map.Entry<JsonObject, BuiltConfig> entry : CONFIGS.entrySet()) {
File cfgFile = new File(cfgPath.toFile(), entry.getValue().fileName+".json");
cfgPath.toFile().mkdirs();
FileUtils.write(cfgFile, GSON.toJson(entry.getKey()), StandardCharsets.UTF_8);
}
ListHandler.initConfigLists();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void registerConfig(BuiltConfig config) {
try {
JsonObject configJson = new JsonObject();
for (PropertyData property : config.properties) buildProperty(configJson, property);
for (BuiltCategory category : config.categories) buildCategory(configJson, category);
CONFIGS.put(configJson, config);
}catch (Exception e) {
e.printStackTrace();
}
}
private static void buildCategory(JsonObject builder, BuiltCategory category) throws IllegalAccessException {
JsonObject categoryJson = new JsonObject();
if (category.categoryDesc != null) categoryJson.addProperty("//"+category.category, category.categoryDesc);
for (PropertyData property : category.properties) buildProperty(categoryJson, property);
for (BuiltCategory builtCategory : category.categories) buildCategory(categoryJson, builtCategory);
builder.add(category.category, categoryJson);
}
@SuppressWarnings("unchecked")
private static void buildProperty(JsonObject builder, PropertyData data) throws IllegalAccessException {
AnnotationData annotationData = data.getData();
builder.addProperty("//"+data.getId(), annotationData.description());
switch (annotationData.type()) {
case BOOLEAN:
builder.addProperty(data.getId(), data.getBoolean());
data.setSetter((b) -> {builder.addProperty(data.getId(), (boolean)b); data.setBoolean((boolean)b);});
break;
case INT:
builder.addProperty(data.getId(), data.getInt());
data.setSetter((b) -> {builder.addProperty(data.getId(), (int)b); data.setInt((int)b);});
break;
case DOUBLE:
builder.addProperty(data.getId(), data.getDouble());
data.setSetter((b) -> {builder.addProperty(data.getId(), (double)b); data.setDouble((double)b);});
break;
case STRING_ARRAY:
JsonArray arr = new JsonArray();
for(String s : data.getStringArray())
arr.add(s);
builder.add(data.getId(), arr);
data.setSetter(list -> {
JsonArray overwrite = new JsonArray();
for(String s : (List<String>)list)
overwrite.add(s);
builder.add(data.getId(), overwrite);
data.setStringArray(((List<?>) list).toArray(new String[0]));
});
break;
default:
throw new IllegalAccessException("Unknown property type.");
}
}
}

View File

@ -0,0 +1,36 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.events;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import tschipp.carryon.CarryOnCommonClient;
public class ClientEvents {
public static void registerEvents()
{
ClientTickEvents.END_CLIENT_TICK.register(mc -> {
CarryOnCommonClient.checkForKeybinds();
CarryOnCommonClient.onCarryClientTick();
});
}
}

View File

@ -0,0 +1,177 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.events;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents;
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.CommonLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.event.player.*;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.packs.PackType;
import net.minecraft.world.InteractionResult;
import tschipp.carryon.CarryOnCommon;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.common.carry.PickupHandler;
import tschipp.carryon.common.carry.PlacementHandler;
import tschipp.carryon.common.scripting.ScriptReloadListener;
import tschipp.carryon.compat.ArchitecturyCompat;
import tschipp.carryon.config.ConfigLoader;
import tschipp.carryon.scripting.IdentifiableScriptReloadListener;
public class CommonEvents {
public static void registerEvents() {
CommonLifecycleEvents.TAGS_LOADED.register((registries, client) -> {
if(!client)
ConfigLoader.onConfigLoaded(registries);
});
UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> {
if(world.isClientSide())
return InteractionResult.PASS;
BlockPos pos = hitResult.getBlockPos();
Direction facing = hitResult.getDirection();
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(!carry.isCarrying())
{
if (PickupHandler.tryPickUpBlock((ServerPlayer) player, pos, world, (pState, pPos) -> {
boolean success = PlayerBlockBreakEvents.BEFORE.invoker().beforeBlockBreak(world, player, pPos, pState, world.getBlockEntity(pPos));
return success;
}))
return InteractionResult.SUCCESS;
return InteractionResult.PASS;
}
else
{
if(carry.isCarrying(CarryOnData.CarryType.BLOCK))
{
if(PlacementHandler.tryPlaceBlock((ServerPlayer) player, pos, facing, (pState, pPos) -> {
return ArchitecturyCompat.sendPlaceEvent(world, pState, pPos, player);
}))
return InteractionResult.SUCCESS;
}
else
{
if(PlacementHandler.tryPlaceEntity((ServerPlayer) player, pos, facing, null))
return InteractionResult.SUCCESS;
}
//Fail here, so that we don't interact with placed things
return InteractionResult.FAIL;
}
});
UseEntityCallback.EVENT.register((player, level, hand, entity, hitResult) -> {
if(level.isClientSide())
return InteractionResult.PASS;
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (!carry.isCarrying()) {
if (PickupHandler.tryPickupEntity((ServerPlayer) player, entity, null)) {
return InteractionResult.SUCCESS;
}
}
else if(carry.isCarrying(CarryOnData.CarryType.ENTITY) || carry.isCarrying(CarryType.PLAYER))
{
PlacementHandler.tryStackEntity((ServerPlayer) player, entity);
}
return InteractionResult.PASS;
});
CommandRegistrationCallback.EVENT.register(((dispatcher, registryAccess, environment) -> {
CarryOnCommon.registerCommands(dispatcher);
}));
ResourceManagerHelper.get(PackType.SERVER_DATA).registerReloadListener(new IdentifiableScriptReloadListener());
ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS.register((player, joined) -> {
ScriptReloadListener.syncScriptsWithClient(player);
});
ServerTickEvents.END_SERVER_TICK.register(server -> {
for(ServerPlayer player : server.getPlayerList().getPlayers())
CarryOnCommon.onCarryTick(player);
});
ServerPlayerEvents.COPY_FROM.register(((oldPlayer, newPlayer, alive) -> {
PlacementHandler.placeCarriedOnDeath(oldPlayer, newPlayer, !alive);
}));
PlayerBlockBreakEvents.BEFORE.register(((world, player, pos, state, blockEntity) -> {
if(!CarryOnCommon.onTryBreakBlock(player))
return false;
return true;
}));
AttackBlockCallback.EVENT.register(((player, world, hand, pos, direction) -> {
if(!CarryOnCommon.onTryBreakBlock(player))
return InteractionResult.SUCCESS;
return InteractionResult.PASS;
}));
AttackEntityCallback.EVENT.register(((player, world, hand, entity, hitResult) -> {
if(!CarryOnCommon.onAttackedByPlayer(player))
return InteractionResult.SUCCESS;
return InteractionResult.PASS;
}));
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
CarryOnCommon.onRiderDisconnected(handler.getPlayer());
});
ServerLivingEntityEvents.ALLOW_DEATH.register((entity, damageSource, damageAmount) -> {
if(entity instanceof ServerPlayer sp) {
CarryOnCommon.onRiderDisconnected(sp);
}
return true;
});
ServerLivingEntityEvents.ALLOW_DAMAGE.register((entity, source, amount) -> {
if(entity instanceof ServerPlayer sp) {
CarryOnCommon.onPlayerAttacked(sp);
}
return true;
});
}
}

View File

@ -0,0 +1,66 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.mixin;
import com.llamalad7.mixinextras.MixinExtrasBootstrap;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import java.util.List;
import java.util.Set;
public class CarryOnMixinConfigPlugin implements IMixinConfigPlugin {
@Override
public void onLoad(String mixinPackage) {
MixinExtrasBootstrap.init();
}
@Override
public String getRefMapperConfig() {
return null;
}
@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
return true;
}
@Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
}
@Override
public List<String> getMixins() {
return null;
}
@Override
public void postApply(String targetClassName, org.objectweb.asm.tree.ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}
@Override
public void preApply(String targetClassName, org.objectweb.asm.tree.ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}
}

View File

@ -0,0 +1,45 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.mixin;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.ItemInHandRenderer;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import tschipp.carryon.client.render.CarriedObjectRender;
@Mixin(ItemInHandRenderer.class)
public class ItemInHandRendererMixin
{
@Inject(at = @At(value = "HEAD"), method = "renderArmWithItem(Lnet/minecraft/client/player/AbstractClientPlayer;FFLnet/minecraft/world/InteractionHand;FLnet/minecraft/world/item/ItemStack;FLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;I)V", cancellable = true)
private void renderArmWithItem(AbstractClientPlayer player, float partialTick, float pitch, InteractionHand hand, float swingProgress, ItemStack item, float equippedProgress, PoseStack poseStack, SubmitNodeCollector nodeCollector, int packedLight, CallbackInfo ci)
{
if(CarriedObjectRender.draw(player, poseStack, packedLight, partialTick,nodeCollector,true))
ci.cancel();
}
}

View File

@ -0,0 +1,50 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.mixin;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import tschipp.carryon.Constants;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.common.carry.PlacementHandler;
@Mixin(Player.class)
public class PlayerMixinFabric
{
@Inject(at = @At("HEAD"), method = "hurtServer(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/damagesource/DamageSource;F)Z")
private void onHurt(ServerLevel level, DamageSource damageSource, float amount, CallbackInfoReturnable<Boolean> cir) {
if(Constants.COMMON_CONFIG.settings.dropCarriedWhenHit)
{
Player player = ((Player)(Object)this);
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying())
PlacementHandler.placeCarried((ServerPlayer)player);
}
}
}

View File

@ -0,0 +1,49 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.mixin;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
@Mixin(Screen.class)
public class ScreenMixin
{
@Inject(at = @At(value = "TAIL"), method = "init(II)V")
private void onInit(int width, int height, CallbackInfo ci)
{
Minecraft mc = Minecraft.getInstance();
Player player = mc.player;
if((Object)this instanceof AbstractContainerScreen && player != null)
{
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying())
mc.setScreen((Screen)null);
}
}
}

View File

@ -0,0 +1,33 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.platform;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.platform.services.IGamestagePlatformHelper;
public class FabricGamestagesHelper implements IGamestagePlatformHelper
{
@Override
public boolean hasStage(Player player, String stage)
{
return true;
}
}

View File

@ -0,0 +1,114 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.platform;
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.Identifier;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import tschipp.carryon.CarryOnFabricClientMod;
import tschipp.carryon.CarryOnFabricMod;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.config.BuiltConfig;
import tschipp.carryon.config.fabric.ConfigLoaderImpl;
import tschipp.carryon.networking.PacketBase;
import tschipp.carryon.platform.services.IPlatformHelper;
import java.util.function.BiConsumer;
public class FabricPlatformHelper implements IPlatformHelper {
@Override
public String getPlatformName() {
return "Fabric";
}
@Override
public boolean isModLoaded(String modId) {
return FabricLoader.getInstance().isModLoaded(modId);
}
@Override
public boolean isDevelopmentEnvironment() {
return FabricLoader.getInstance().isDevelopmentEnvironment();
}
@Override
public void registerConfig(BuiltConfig cfg) {
ConfigLoaderImpl.registerConfig(cfg);
}
@SuppressWarnings("unchecked")
@Override
public <T extends PacketBase, B extends FriendlyByteBuf> void registerServerboundPacket(CustomPacketPayload.Type<T> type, Class<T> clazz, StreamCodec<B, T> codec, BiConsumer<T, Player> handler, Object... args)
{
PayloadTypeRegistry.playC2S().register(type, (StreamCodec<RegistryFriendlyByteBuf, T>)codec);
ServerPlayNetworking.registerGlobalReceiver(type, (T packet, ServerPlayNetworking.Context context) -> {
context.server().execute(() -> {
handler.accept(packet, context.player());
});
});
}
@SuppressWarnings("unchecked")
@Override
public <T extends PacketBase, B extends FriendlyByteBuf> void registerClientboundPacket(CustomPacketPayload.Type<T> type, Class<T> clazz, StreamCodec<B, T> codec, BiConsumer<T, Player> handler, Object... args)
{
boolean client = (boolean)args[0];
if(!client)
PayloadTypeRegistry.playS2C().register(type, (StreamCodec<RegistryFriendlyByteBuf, T>)codec);
else
CarryOnFabricClientMod.registerClientboundPacket(type, handler);
}
@Override
public void sendPacketToServer(Identifier id, PacketBase packet)
{
CarryOnFabricClientMod.sendPacketToServer(packet);
}
@Override
public void sendPacketToPlayer(Identifier id, PacketBase packet, ServerPlayer player)
{
ServerPlayNetworking.send(player, packet);
}
@Override
public CarryOnData getCarryData(Player player) {
CarryOnData data = player.getAttachedOrCreate(CarryOnFabricMod.CARRY_ON_DATA_ATTACHMENT_TYPE);
return data.clone();
}
@Override
public void setCarryData(Player player, CarryOnData data) {
player.setAttached(CarryOnFabricMod.CARRY_ON_DATA_ATTACHMENT_TYPE, data);
}
}

View File

@ -0,0 +1,35 @@
/*
* GNU Lesser General Public License v3
* Copyright (C) 2024 Tschipp
* mrtschipp@gmail.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package tschipp.carryon.scripting;
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
import net.minecraft.resources.Identifier;
import tschipp.carryon.Constants;
import tschipp.carryon.common.scripting.ScriptReloadListener;
public class IdentifiableScriptReloadListener extends ScriptReloadListener implements IdentifiableResourceReloadListener
{
@Override
public Identifier getFabricId()
{
return Identifier.fromNamespaceAndPath(Constants.MOD_ID, "carryon_scripts");
}
}

View File

@ -0,0 +1 @@
tschipp.carryon.platform.FabricGamestagesHelper

View File

@ -0,0 +1 @@
tschipp.carryon.platform.FabricPlatformHelper

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