Compare commits

...

109 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
143 changed files with 5147 additions and 1552 deletions

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.

4
.gitignore vendored
View File

@ -21,3 +21,7 @@ build
# other # other
eclipse eclipse
run run
runs
# vscode
.vscode/*

View File

@ -1,60 +1,51 @@
plugins { plugins {
id 'java' id 'multiloader-common'
id 'org.spongepowered.gradle.vanilla' version '0.2.1-SNAPSHOT' id 'net.neoforged.moddev'
id 'maven-publish'
}
archivesBaseName = "${mod_id}-common-${minecraft_version}"
minecraft {
version(minecraft_version)
runs {
if (project.hasProperty('common_runs_enabled') ? project.findProperty('common_runs_enabled').toBoolean() : true) {
server(project.hasProperty('common_server_run_name') ? project.findProperty('common_server_run_name') : 'vanilla_server') {
workingDirectory(this.file("run"))
}
client(project.hasProperty('common_client_run_name') ? project.findProperty('common_client_run_name') : 'vanilla_client') {
workingDirectory(this.file("run"))
}
}
}
} }
repositories { repositories {
maven {
name = "Shedaniel"
url "https://maven.shedaniel.me/"
}
maven { url 'https://jitpack.io' } 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 { dependencies {
compileOnly group:'org.spongepowered', name:'mixin', version:'0.8.5' compileOnly group: 'org.spongepowered', name: 'mixin', version: '0.8.5'
implementation group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.1' // fabric and neoforge both bundle mixinextras, so it is safe to use it in common
implementation("com.github.llamalad7.mixinextras:mixinextras-common:${mixinextras_version}") implementation("io.github.llamalad7:mixinextras-common:${mixinextras_version}")
annotationProcessor("com.github.llamalad7.mixinextras:mixinextras-common:${mixinextras_version}") annotationProcessor("io.github.llamalad7:mixinextras-common:${mixinextras_version}")
compileOnly("me.shedaniel.cloth:cloth-config-neoforge:${cloth_config_version}")
} }
processResources { configurations {
commonJava {
def buildProps = project.properties.clone() canBeResolved = false
canBeConsumed = true
filesMatching(['pack.mcmeta']) { }
commonResources {
expand buildProps canBeResolved = false
canBeConsumed = true
} }
} }
publishing { artifacts {
publications { commonJava sourceSets.main.java.sourceDirectories.singleFile
mavenJava(MavenPublication) { commonResources sourceSets.main.resources.sourceDirectories.singleFile
groupId project.group
artifactId project.archivesBaseName
version project.version
from components.java
}
}
repositories {
maven {
url "file://" + System.getenv("local_maven")
}
}
} }

View File

@ -1,10 +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; package tschipp.carryon;
import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.CommandDispatcher;
import net.minecraft.commands.CommandSourceStack; 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.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@ -15,6 +37,7 @@ import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.common.carry.PlacementHandler; import tschipp.carryon.common.carry.PlacementHandler;
import tschipp.carryon.common.command.CommandCarryOn; import tschipp.carryon.common.command.CommandCarryOn;
import tschipp.carryon.config.ConfigLoader; import tschipp.carryon.config.ConfigLoader;
import tschipp.carryon.networking.clientbound.ClientboundStartRidingOtherPlayerPacket;
import tschipp.carryon.networking.clientbound.ClientboundStartRidingPacket; import tschipp.carryon.networking.clientbound.ClientboundStartRidingPacket;
import tschipp.carryon.networking.clientbound.ClientboundSyncScriptsPacket; import tschipp.carryon.networking.clientbound.ClientboundSyncScriptsPacket;
import tschipp.carryon.networking.serverbound.ServerboundCarryKeyPressedPacket; import tschipp.carryon.networking.serverbound.ServerboundCarryKeyPressedPacket;
@ -22,36 +45,49 @@ import tschipp.carryon.platform.Services;
public class CarryOnCommon public class CarryOnCommon
{ {
public static void registerServerPackets() 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( Services.PLATFORM.registerServerboundPacket(
Constants.PACKET_ID_KEY_PRESSED, ServerboundCarryKeyPressedPacket.TYPE,
0,
ServerboundCarryKeyPressedPacket.class, ServerboundCarryKeyPressedPacket.class,
ServerboundCarryKeyPressedPacket::toBytes, ServerboundCarryKeyPressedPacket.CODEC,
ServerboundCarryKeyPressedPacket::new, ServerboundCarryKeyPressedPacket::handle,
ServerboundCarryKeyPressedPacket::handle args
); );
} }
public static void registerClientPackets() public static void registerClientPackets(Object... args)
{ {
Services.PLATFORM.registerClientboundPacket( Services.PLATFORM.registerClientboundPacket(
Constants.PACKET_ID_START_RIDING, ClientboundStartRidingPacket.TYPE,
1,
ClientboundStartRidingPacket.class, ClientboundStartRidingPacket.class,
ClientboundStartRidingPacket::toBytes, ClientboundStartRidingPacket.CODEC,
ClientboundStartRidingPacket::new, ClientboundStartRidingPacket::handle,
ClientboundStartRidingPacket::handle args
); );
Services.PLATFORM.registerClientboundPacket( Services.PLATFORM.registerClientboundPacket(
Constants.PACKET_ID_SYNC_SCRIPTS, ClientboundSyncScriptsPacket.TYPE,
2,
ClientboundSyncScriptsPacket.class, ClientboundSyncScriptsPacket.class,
ClientboundSyncScriptsPacket::toBytes, ClientboundSyncScriptsPacket.CODEC,
ClientboundSyncScriptsPacket::new, ClientboundSyncScriptsPacket::handle,
ClientboundSyncScriptsPacket::handle args
);
Services.PLATFORM.registerClientboundPacket(
ClientboundStartRidingOtherPlayerPacket.TYPE,
ClientboundStartRidingOtherPlayerPacket.class,
ClientboundStartRidingOtherPlayerPacket.CODEC,
ClientboundStartRidingOtherPlayerPacket::handle,
args
); );
} }
@ -72,20 +108,19 @@ public class CarryOnCommon
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying()) 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()) if(carry.getActiveScript().isPresent())
{ {
String cmd = carry.getActiveScript().get().scriptEffects().commandLoop(); String cmd = carry.getActiveScript().get().scriptEffects().commandLoop();
if(!cmd.isEmpty()) if(!cmd.isEmpty())
player.getServer().getCommands().performPrefixedCommand(player.getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().getName() + " run " + cmd); player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
} }
if (!Constants.COMMON_CONFIG.settings.slownessInCreative && player.isCreative())
return;
player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 1, potionLevel(carry, player.level), false, false));
Inventory inv = player.getInventory(); Inventory inv = player.getInventory();
inv.selected = carry.getSelected(); inv.setSelectedSlot(carry.getSelected());
} }
} }
@ -119,7 +154,7 @@ public class CarryOnCommon
public static void onPlayerAttacked(Player player) public static void onPlayerAttacked(Player player)
{ {
if (Constants.COMMON_CONFIG.settings.dropCarriedWhenHit && !player.level.isClientSide) if (Constants.COMMON_CONFIG.settings.dropCarriedWhenHit && !player.level().isClientSide())
{ {
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (carry.isCarrying()) if (carry.isCarrying())
@ -130,8 +165,18 @@ public class CarryOnCommon
} }
} }
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);
}
}
}
private static int potionLevel(CarryOnData carry, Level level)
public static int potionLevel(CarryOnData carry, Level level)
{ {
if(carry.isCarrying(CarryType.PLAYER)) if(carry.isCarrying(CarryType.PLAYER))
return 1; return 1;

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@ -14,11 +34,11 @@ public class CarryOnCommonClient
Player player = mc.player; Player player = mc.player;
if(player != null) { if(player != null) {
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
if ((CarryOnKeybinds.carryKey.isUnbound() ? player.isShiftKeyDown() : (CarryOnKeybinds.carryKey.isDown() || checkMouse())) && !carry.isKeyPressed()) { if ((CarryOnKeybinds.carryKey.isUnbound() ? player.isShiftKeyDown() : (CarryOnKeybinds.carryKey.isDown())) && !carry.isKeyPressed()) {
CarryOnKeybinds.onCarryKey(true); CarryOnKeybinds.onCarryKey(true);
carry.setKeyPressed(true); carry.setKeyPressed(true);
CarryOnDataManager.setCarryData(player, carry); CarryOnDataManager.setCarryData(player, carry);
} else if (!(CarryOnKeybinds.carryKey.isUnbound() ? player.isShiftKeyDown() : (CarryOnKeybinds.carryKey.isDown() || checkMouse()) ) && carry.isKeyPressed()) { } else if (!(CarryOnKeybinds.carryKey.isUnbound() ? player.isShiftKeyDown() : (CarryOnKeybinds.carryKey.isDown() ) ) && carry.isKeyPressed()) {
CarryOnKeybinds.onCarryKey(false); CarryOnKeybinds.onCarryKey(false);
carry.setKeyPressed(false); carry.setKeyPressed(false);
CarryOnDataManager.setCarryData(player, carry); CarryOnDataManager.setCarryData(player, carry);
@ -26,20 +46,16 @@ public class CarryOnCommonClient
} }
} }
private static boolean checkMouse()
{
Minecraft mc = Minecraft.getInstance();
return (CarryOnKeybinds.carryKey.matchesMouse(0) && mc.mouseHandler.isLeftPressed()) || (CarryOnKeybinds.carryKey.matchesMouse(1) && mc.mouseHandler.isRightPressed()) || (CarryOnKeybinds.carryKey.matchesMouse(3) && mc.mouseHandler.isMiddlePressed());
}
public static void onCarryClientTick() public static void onCarryClientTick() {
{
Player player = Minecraft.getInstance().player; Player player = Minecraft.getInstance().player;
if(player != null) { if (player != null) {
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying()) if (carry.isCarrying()) {
{ int wantedSlot = carry.getSelected();
player.getInventory().selected = carry.getSelected(); if (player.getInventory().getSelectedSlot() != wantedSlot) {
player.getInventory().setSelectedSlot(wantedSlot);
}
} }
} }
} }
@ -48,4 +64,4 @@ public class CarryOnCommonClient
{ {
return Minecraft.getInstance().player; return Minecraft.getInstance().player;
} }
} }

View File

@ -1,6 +1,26 @@
/*
* 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; package tschipp.carryon;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.Identifier;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import tschipp.carryon.common.config.CarryConfig; import tschipp.carryon.common.config.CarryConfig;
@ -14,8 +34,10 @@ public class Constants {
public static final CarryConfig.Common COMMON_CONFIG = new CarryConfig.Common(); public static final CarryConfig.Common COMMON_CONFIG = new CarryConfig.Common();
public static final CarryConfig.Client CLIENT_CONFIG = new CarryConfig.Client(); public static final CarryConfig.Client CLIENT_CONFIG = new CarryConfig.Client();
public static final ResourceLocation PACKET_ID_KEY_PRESSED = new ResourceLocation(Constants.MOD_ID, "key_pressed"); public static final Identifier PACKET_ID_KEY_PRESSED = Identifier.fromNamespaceAndPath(Constants.MOD_ID, "key_pressed");
public static final ResourceLocation PACKET_ID_START_RIDING = new ResourceLocation(Constants.MOD_ID, "start_riding"); public static final Identifier PACKET_ID_START_RIDING = Identifier.fromNamespaceAndPath(Constants.MOD_ID, "start_riding");
public static final ResourceLocation PACKET_ID_SYNC_SCRIPTS = new ResourceLocation(Constants.MOD_ID, "sync_scripts"); 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

@ -1,7 +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.client.keybinds; package tschipp.carryon.client.keybinds;
import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.platform.InputConstants;
import net.minecraft.client.KeyMapping; import net.minecraft.client.KeyMapping;
import net.minecraft.client.KeyMapping.Category;
import net.minecraft.resources.Identifier;
import tschipp.carryon.Constants; import tschipp.carryon.Constants;
import tschipp.carryon.networking.serverbound.ServerboundCarryKeyPressedPacket; import tschipp.carryon.networking.serverbound.ServerboundCarryKeyPressedPacket;
import tschipp.carryon.platform.Services; import tschipp.carryon.platform.Services;
@ -14,10 +36,9 @@ public class CarryOnKeybinds
public static void registerKeybinds(Consumer<KeyMapping> registrar) public static void registerKeybinds(Consumer<KeyMapping> registrar)
{ {
if(Services.PLATFORM.isModLoaded("amecsapi")) Category category = Category.register(Identifier.fromNamespaceAndPath(Constants.MOD_ID,"key.carry.category"));
carryKey = new ConflictFreeKeyMapping("key.carry.desc", InputConstants.KEY_LSHIFT, "key.carry.category");
else carryKey = new KeyMapping("key.carry.desc", InputConstants.KEY_LSHIFT, category);
carryKey = new ConflictFreeKeyMapping("key.carry.desc", Services.PLATFORM.getPlatformName().equals("Forge") ? InputConstants.KEY_LSHIFT : InputConstants.UNKNOWN.getValue(), "key.carry.category");
registrar.accept(carryKey); registrar.accept(carryKey);
} }

View File

@ -1,23 +0,0 @@
package tschipp.carryon.client.keybinds;
import com.mojang.blaze3d.platform.InputConstants.Type;
import net.minecraft.client.KeyMapping;
public class ConflictFreeKeyMapping extends KeyMapping
{
public ConflictFreeKeyMapping(String $$0, int $$1, String $$2)
{
super($$0, $$1, $$2);
}
public ConflictFreeKeyMapping(String $$0, Type $$1, int $$2, String $$3)
{
super($$0, $$1, $$2, $$3);
}
@Override
public boolean same(KeyMapping $$0)
{
return false;
}
}

View File

@ -1,14 +1,34 @@
/*
* 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; package tschipp.carryon.client.modeloverride;
import com.mojang.brigadier.StringReader; import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult; import com.mojang.serialization.DataResult;
import net.minecraft.commands.arguments.blocks.BlockStateParser; import net.minecraft.commands.arguments.blocks.BlockStateParser;
import net.minecraft.commands.arguments.blocks.BlockStateParser.BlockResult; import net.minecraft.commands.arguments.blocks.BlockStateParser.BlockResult;
import net.minecraft.commands.arguments.item.ItemParser; import net.minecraft.commands.arguments.item.ItemParser;
import net.minecraft.commands.arguments.item.ItemParser.ItemResult; import net.minecraft.commands.arguments.item.ItemParser.ItemResult;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@ -19,27 +39,18 @@ import tschipp.carryon.common.scripting.Matchables.NBTCondition;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Map; import java.util.Map;
public class ModelOverride public class ModelOverride {
{
public static Codec<ModelOverride> CODEC = Codec.STRING.comapFlatMap(ModelOverride::of, override -> override.raw);
private String raw;
private BlockResult parsedBlock; private BlockResult parsedBlock;
private Type type;
private Either<ItemResult, BlockResult> parsedRHS;
private Either<ItemStack, BlockState> renderObject; private Either<ItemStack, BlockState> renderObject;
private ModelOverride(String raw, BlockResult parsedBlock, Type type, Either<ItemResult, BlockResult> parsedRHS) private ModelOverride(String raw, BlockResult parsedBlock, Type type, Either<ItemResult, BlockResult> parsedRHS)
{ {
this.raw = raw;
this.parsedBlock = parsedBlock; this.parsedBlock = parsedBlock;
this.type = type;
this.parsedRHS = parsedRHS;
parsedRHS.ifLeft(res -> { parsedRHS.ifLeft(res -> {
ItemStack stack = new ItemStack(res.item()); ItemStack stack = new ItemStack(res.item());
if(res.nbt() != null) if(res.components() != null)
stack.setTag(res.nbt()); stack.applyComponents(res.components());
this.renderObject = Either.left(stack); this.renderObject = Either.left(stack);
}); });
@ -49,7 +60,7 @@ public class ModelOverride
}); });
} }
public static DataResult<ModelOverride> of(String str) public static DataResult<ModelOverride> of(String str, HolderLookup.Provider provider)
{ {
if(!str.contains("->")) if(!str.contains("->"))
return DataResult.error(() -> str + " must contain -> Arrow!"); return DataResult.error(() -> str + " must contain -> Arrow!");
@ -60,7 +71,7 @@ public class ModelOverride
BlockResult res; BlockResult res;
try { try {
res = BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK.asLookup(), from, true); res = BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK, from, true);
} catch (Exception e) { } catch (Exception e) {
return DataResult.error(() -> "Error while parsing " + from + ":" + e.getMessage()); return DataResult.error(() -> "Error while parsing " + from + ":" + e.getMessage());
} }
@ -78,9 +89,9 @@ public class ModelOverride
Either<ItemResult, BlockResult> either; Either<ItemResult, BlockResult> either;
try { try {
if(type == Type.ITEM) if(type == Type.ITEM)
either = Either.left(ItemParser.parseForItem(BuiltInRegistries.ITEM.asLookup(), new StringReader(to))); either = Either.left(new ItemParser(provider).parse(new StringReader(to)));
else else
either = Either.right(BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK.asLookup(), to, true)); either = Either.right(BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK, to, true));
}catch (CommandSyntaxException e) { }catch (CommandSyntaxException e) {
String finalTo = to; String finalTo = to;
return DataResult.error(() -> "Error while parsing " + finalTo + ":" + e.getMessage()); return DataResult.error(() -> "Error while parsing " + finalTo + ":" + e.getMessage());

View File

@ -1,6 +1,27 @@
/*
* 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; package tschipp.carryon.client.modeloverride;
import com.mojang.serialization.DataResult; import com.mojang.serialization.DataResult;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import tschipp.carryon.Constants; import tschipp.carryon.Constants;
@ -14,13 +35,13 @@ public class ModelOverrideHandler
{ {
private static List<ModelOverride> OVERRIDES = new ArrayList<>(); private static List<ModelOverride> OVERRIDES = new ArrayList<>();
public static void initModelOverrides() public static void initModelOverrides(HolderLookup.Provider provider)
{ {
OVERRIDES.clear(); OVERRIDES.clear();
for(String ov : Constants.CLIENT_CONFIG.modelOverrides) for(String ov : Constants.CLIENT_CONFIG.modelOverrides)
{ {
addFromString(ov); addFromString(ov, provider);
} }
} }
@ -34,9 +55,9 @@ public class ModelOverrideHandler
return Optional.empty(); return Optional.empty();
} }
public static void addFromString(String str) public static void addFromString(String str, HolderLookup.Provider provider)
{ {
DataResult<ModelOverride> res = ModelOverride.of(str); DataResult<ModelOverride> res = ModelOverride.of(str, provider);
if(res.result().isPresent()) if(res.result().isPresent())
{ {
ModelOverride override = res.result().get(); ModelOverride override = res.result().get();

View File

@ -1,51 +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.client.render; package tschipp.carryon.client.render;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.math.Axis;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.MultiBufferSource.BufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher; import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.entity.state.EntityRenderState;
import net.minecraft.client.resources.model.BakedModel; 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.Entity;
import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import tschipp.carryon.Constants;
import tschipp.carryon.common.carry.CarryOnData; import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnData.CarryType; import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.carry.CarryOnDataManager; import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.common.scripting.CarryOnScript;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptRender; import tschipp.carryon.common.scripting.CarryOnScript.ScriptRender;
import tschipp.carryon.platform.Services; import tschipp.carryon.platform.Services;
import java.util.Map;
import java.util.Optional;
public class CarriedObjectRender public class CarriedObjectRender
{ {
public static boolean draw(Player player, PoseStack matrix, int light, float partialTicks,SubmitNodeCollector nodeCollector, boolean firstPerson)
public static boolean drawFirstPerson(Player player, MultiBufferSource buffer, PoseStack matrix, int light, float partialTicks)
{ {
if(Services.PLATFORM.isModLoaded("firstperson") || Services.PLATFORM.isModLoaded("firstpersonmod")) if(Services.PLATFORM.isModLoaded("firstperson") || Services.PLATFORM.isModLoaded("firstpersonmod") || player == null)
return false; return false;
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
try { try {
if (carry.isCarrying(CarryType.BLOCK)) if (carry.isCarrying(CarryType.BLOCK))
drawFirstPersonBlock(player, buffer, matrix, light, CarryRenderHelper.getRenderState(player)); drawBlock(player, matrix, light, CarryRenderHelper.getRenderState(player), nodeCollector, firstPerson, partialTicks);
else if (carry.isCarrying(CarryType.ENTITY)) else if (carry.isCarrying(CarryType.ENTITY))
drawFirstPersonEntity(player, buffer, matrix, light, partialTicks); drawEntity(player, matrix, light, partialTicks, nodeCollector, firstPerson);
} }
catch (Exception e) catch (Exception e)
{ {
@ -65,193 +75,59 @@ public class CarriedObjectRender
return carry.isCarrying(); return carry.isCarrying();
} }
private static void drawFirstPersonBlock(Player player, MultiBufferSource buffer, PoseStack matrix, int light, BlockState state) private static void drawBlock(Player player, PoseStack matrix, int light, BlockState state, SubmitNodeCollector nodeCollector, boolean firstPerson, float partialTicks)
{ {
matrix.pushPose();
matrix.scale(2.5f, 2.5f, 2.5f);
matrix.translate(0, -0.5, -1);
RenderSystem.enableBlend();
RenderSystem.disableCull();
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
ItemStackRenderState renderState = new ItemStackRenderState();
var layer = renderState.newLayer();
layer.setRenderType(RenderTypes.glint());
if (Constants.CLIENT_CONFIG.facePlayer != CarryRenderHelper.isChest(state.getBlock())) { matrix.pushPose();
matrix.mulPose(Axis.YP.rotationDegrees(180));
matrix.mulPose(Axis.XN.rotationDegrees(8));
} else {
matrix.mulPose(Axis.XP.rotationDegrees(8));
}
if(carry.getActiveScript().isPresent()) PoseStack renderPose = CarryRenderHelper.setupBlockTransformations(player, matrix, carry, firstPerson);
CarryRenderHelper.performScriptTransformation(matrix, carry.getActiveScript().get());
RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS); ItemStack renderStack = CarryRenderHelper.getRenderItemStack(player);
Minecraft.getInstance().getItemModelResolver().updateForTopItem(renderState, renderStack, ItemDisplayContext.NONE, player.level(), null, 0);
ItemStack stack = new ItemStack(state.getBlock().asItem()); renderState.submit(renderPose, nodeCollector, light, OverlayTexture.NO_OVERLAY, 0);
BakedModel model = CarryRenderHelper.getRenderBlock(player);
CarryRenderHelper.renderBakedModel(stack, matrix, buffer, light, model);
RenderSystem.enableCull();
RenderSystem.disableBlend();
matrix.popPose(); matrix.popPose();
} }
private static void drawFirstPersonEntity(Player player, MultiBufferSource buffer, PoseStack matrix, int light, float partialTicks) { private static void drawEntity(Player player, PoseStack matrix, int light, float partialTicks,SubmitNodeCollector nodeCollector, boolean firstPerson) {
EntityRenderDispatcher manager = Minecraft.getInstance().getEntityRenderDispatcher(); EntityRenderDispatcher manager = Minecraft.getInstance().getEntityRenderDispatcher();
Entity entity = CarryRenderHelper.getRenderEntity(player); Entity entity = CarryRenderHelper.getRenderEntity(player);
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (entity != null) if (entity == null)
{ return;
Vec3 playerpos = CarryRenderHelper.getExactPos(player, partialTicks);
entity.setPos(playerpos.x, playerpos.y, playerpos.z); Vec3 playerpos = CarryRenderHelper.getExactPos(player, partialTicks);
entity.xRotO = 0.0f;
entity.yRotO = 0.0f;
entity.setYHeadRot(0.0f);
float height = entity.getBbHeight(); entity.setPos(playerpos.x, playerpos.y, playerpos.z);
float width = entity.getBbWidth(); entity.xRotO = 0.0f;
entity.yRotO = 0.0f;
entity.setYHeadRot(0.0f);
matrix.pushPose(); matrix.pushPose();
matrix.scale(0.8f, 0.8f, 0.8f);
matrix.mulPose(Axis.YP.rotationDegrees(180));
matrix.translate(0.0, -height - .1, width + 0.1);
manager.setRenderShadow(false); CarryRenderHelper.setupEntityTransformations(player, matrix, carry, firstPerson);
Optional<CarryOnScript> res = carry.getActiveScript(); if (entity instanceof LivingEntity)
if(res.isPresent()) ((LivingEntity) entity).hurtTime = 0;
{
CarryOnScript script = res.get();
CarryRenderHelper.performScriptTransformation(matrix, script);
}
if (entity instanceof LivingEntity) try {
((LivingEntity) entity).hurtTime = 0; 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)
{
}
try { matrix.popPose();
manager.render(entity, 0, 0, 0, 0f, 0, matrix, buffer, light); if(!firstPerson)
}
catch (Exception e)
{
}
manager.setRenderShadow(true);
matrix.popPose(); matrix.popPose();
}
}
// RenderSystem.disableAlphaTest();
}
/**
* Draws the third person view of entities and blocks
* @param partialticks
* @param matrix
*/
public static void drawThirdPerson(float partialticks, PoseStack matrix) {
Minecraft mc = Minecraft.getInstance();
Level level = mc.level;
int light = 0;
int perspective = CarryRenderHelper.getPerspective();
EntityRenderDispatcher manager = mc.getEntityRenderDispatcher();
RenderSystem.enableBlend();
RenderSystem.disableCull();
RenderSystem.disableDepthTest();
Map<RenderType, BufferBuilder> builders = Map.of(
RenderType.glint(), new BufferBuilder(RenderType.glint().bufferSize()),
RenderType.glintDirect(), new BufferBuilder(RenderType.glintDirect().bufferSize()),
RenderType.glintTranslucent(), new BufferBuilder(RenderType.glintTranslucent().bufferSize()),
RenderType.entityGlint(), new BufferBuilder(RenderType.entityGlint().bufferSize()),
RenderType.entityGlintDirect(), new BufferBuilder(RenderType.entityGlintDirect().bufferSize())
);
BufferSource buffer = MultiBufferSource.immediateWithBuffers(builders, Tesselator.getInstance().getBuilder());
for (Player player : level.players())
{
try {
CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (perspective == 0 && player == mc.player && !(Services.PLATFORM.isModLoaded("firstperson") || Services.PLATFORM.isModLoaded("firstpersonmod")))
continue;
light = manager.getPackedLightCoords(player, partialticks);
if (carry.isCarrying(CarryType.BLOCK)) {
BlockState state = CarryRenderHelper.getRenderState(player);
CarryRenderHelper.applyBlockTransformations(player, partialticks, matrix, state.getBlock());
ItemStack tileItem = new ItemStack(state.getBlock().asItem());
BakedModel model = CarryRenderHelper.getRenderBlock(player);
//ModelOverridesHandler.hasCustomOverrideModel(state, tag) ? ModelOverridesHandler.getCustomOverrideModel(state, tag, level, player) : tileItem.isEmpty() ? mc.getBlockRenderer().getBlockModel(state) : mc.getItemRenderer().getModel(tileItem, level, player, 0);
//
Optional<CarryOnScript> res = carry.getActiveScript();
if (res.isPresent()) {
CarryOnScript script = res.get();
CarryRenderHelper.performScriptTransformation(matrix, script);
}
RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS);
RenderSystem.enableCull();
PoseStack.Pose p = matrix.last();
PoseStack copy = new PoseStack();
copy.mulPoseMatrix(p.pose());
matrix.popPose();
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
CarryRenderHelper.renderBakedModel(tileItem, copy, buffer, light, model);
matrix.popPose();
} else if (carry.isCarrying(CarryType.ENTITY)) {
Entity entity = CarryRenderHelper.getRenderEntity(player);
if (entity != null) {
CarryRenderHelper.applyEntityTransformations(player, partialticks, matrix, entity);
manager.setRenderShadow(false);
Optional<CarryOnScript> res = carry.getActiveScript();
if (res.isPresent()) {
CarryOnScript script = res.get();
CarryRenderHelper.performScriptTransformation(matrix, script);
}
if (entity instanceof LivingEntity le)
le.hurtTime = 0;
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
manager.render(entity, 0, 0, 0, 0f, 0, matrix, buffer, light);
matrix.popPose();
manager.setRenderShadow(true);
matrix.popPose();
}
}
}
catch (Exception e)
{
}
}
buffer.endLastBatch();
buffer.endBatch(RenderType.entitySolid(TextureAtlas.LOCATION_BLOCKS));
buffer.endBatch(RenderType.entityCutout(TextureAtlas.LOCATION_BLOCKS));
buffer.endBatch(RenderType.entityCutoutNoCull(TextureAtlas.LOCATION_BLOCKS));
buffer.endBatch(RenderType.entitySmoothCutout(TextureAtlas.LOCATION_BLOCKS));
RenderSystem.enableDepthTest();
RenderSystem.enableCull();
RenderSystem.disableBlend();
}
} }

View File

@ -1,25 +1,42 @@
/*
* 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; package tschipp.carryon.client.render;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis; import com.mojang.math.Axis;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.util.Mth; import net.minecraft.util.ProblemReporter;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Pose; import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.ChestBlock;
import net.minecraft.world.level.block.state.BlockState; 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.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.phys.shapes.VoxelShape;
import org.joml.Quaternionf; import org.joml.Quaternionf;
@ -57,91 +74,60 @@ public class CarryRenderHelper
return Axis.YP.rotationDegrees(getExactBodyRotationDegrees(entity, partialticks)); return Axis.YP.rotationDegrees(getExactBodyRotationDegrees(entity, partialticks));
} }
public static void applyGeneralTransformations(Player player, float partialticks, PoseStack matrix) public static void applyGeneralTransformations(Player player, PoseStack matrix)
{ {
int perspective = CarryRenderHelper.getPerspective();
Quaternionf playerrot = CarryRenderHelper.getExactBodyRotation(player, partialticks);
Vec3 playerpos = CarryRenderHelper.getExactPos(player, partialticks);
Vec3 cameraPos = Minecraft.getInstance().gameRenderer.getMainCamera().getPosition();
Vec3 offset = playerpos.subtract(cameraPos);
Pose pose = player.getPose(); Pose pose = player.getPose();
matrix.pushPose();
matrix.translate(offset.x, offset.y, offset.z);
if (perspective == 2)
playerrot.mul(Axis.YP.rotationDegrees(180));
matrix.mulPose(playerrot);
matrix.pushPose(); matrix.pushPose();
matrix.scale(0.6f, 0.6f, 0.6f); matrix.scale(0.6f, 0.6f, 0.6f);
if (perspective == 2) matrix.translate(0, 0, -1.35);
matrix.translate(0, 0, -1.35);
if (doSneakCheck(player)) if (doSneakCheck(player))
{ {
matrix.translate(0, -0.4, 0); matrix.translate(0, -0.4, 0);
} }
if (pose == Pose.SWIMMING) if (pose == Pose.SWIMMING || pose == Pose.FALL_FLYING)
{ {
float f = player.getSwimAmount(partialticks); matrix.translate(0, 0, 2.5);
float f3 = player.isInWater() ? -90.0F - player.xRotO : -90.0F; matrix.mulPose(Axis.XP.rotationDegrees(90));
float f4 = Mth.lerp(f, 0.0F, f3);
if (perspective == 2)
{
matrix.translate(0, 0, 1.35);
matrix.mulPose(Axis.XP.rotationDegrees(f4));
}
else
matrix.mulPose(Axis.XN.rotationDegrees(f4));
matrix.translate(0, -1.5, -1.848);
if (perspective == 2)
matrix.translate(0, 0, 2.38);
} }
if (pose == Pose.FALL_FLYING) matrix.translate(0, -0.5, 0.65);
{
float f1 = player.getFallFlyingTicks() + partialticks;
float f2 = Mth.clamp(f1 * f1 / 100.0F, 0.0F, 1.0F);
if (!player.isAutoSpinAttack())
{
if (perspective == 2)
matrix.translate(0, 0, 1.35);
if (perspective == 2)
matrix.mulPose(Axis.XP.rotationDegrees(f2 * (-90.0F - player.xRotO)));
else
matrix.mulPose(Axis.XN.rotationDegrees(f2 * (-90.0F - player.xRotO)));
}
Vec3 viewVector = player.getViewVector(partialticks);
Vec3 deltaMovement = player.getDeltaMovement();
double d0 = deltaMovement.horizontalDistanceSqr();
double d1 = deltaMovement.horizontalDistanceSqr();
if (d0 > 0.0D && d1 > 0.0D)
{
double d2 = (deltaMovement.x * viewVector.x + deltaMovement.z * viewVector.z) / (Math.sqrt(d0) * Math.sqrt(d1));
double d3 = deltaMovement.x * viewVector.z - deltaMovement.z * viewVector.x;
matrix.mulPose(Axis.YP.rotation((float) (Math.signum(d3) * Math.acos(d2))));
}
if (perspective != 2)
matrix.translate(0, 0, -1.35);
matrix.translate(0, -0.2, 0);
}
matrix.translate(0, 1.6, 0.65);
} }
public static void applyBlockTransformations(Player player, float partialticks, PoseStack matrix, Block block) public static PoseStack setupBlockTransformations(Player player, PoseStack matrix, CarryOnData carry, boolean firstPerson) {
{ if (firstPerson) {
int perspective = CarryRenderHelper.getPerspective(); matrix.scale(2.5f, 2.5f, 2.5f);
matrix.translate(0, -0.5, -1);
applyGeneralTransformations(player, partialticks, matrix); 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)) if (Constants.CLIENT_CONFIG.facePlayer != CarryRenderHelper.isChest(block))
{ {
@ -150,61 +136,72 @@ public class CarryRenderHelper
// matrix.translate(0, 0, -0.4); // matrix.translate(0, 0, -0.4);
matrix.mulPose(Axis.YP.rotationDegrees(180)); matrix.mulPose(Axis.YP.rotationDegrees(180));
} }
// if(perspective == 1)
// {
// matrix.pushPose();
// //matrix.mulPose(Axis.YP.rotationDegrees(180));
// matrix.popPose();
// }
//else 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 height = getRenderHeight(player);
float offset = (height - 1f) / 1.2f; float offset = (height - 1f) / 1.2f;
matrix.translate(0, -offset, 0); matrix.translate(0, -offset, 0);
} }
public static void applyEntityTransformations(Player player, float partialticks, PoseStack matrix, Entity entity) 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)
{ {
int perspective = CarryRenderHelper.getPerspective();
Pose pose = player.getPose(); Pose pose = player.getPose();
applyGeneralTransformations(player, partialticks, matrix); applyGeneralTransformations(player, matrix);
if (perspective == 2) matrix.mulPose(Axis.XP.rotationDegrees(180));
matrix.translate(0, -1.6, 0.65);
else matrix.translate(0, -3.1, -0.65);
matrix.translate(0, -1.6, -0.65);
matrix.scale(1.666f, 1.666f, 1.666f); matrix.scale(1.666f, 1.666f, 1.666f);
float height = entity.getBbHeight(); float height = entity.getBbHeight();
float width = entity.getBbWidth(); float width = entity.getBbWidth();
float multiplier = height * width; float multiplier = Math.min(9.9f, height * width) ;
entity.yo = 0.0f; entity.yo = 0.0f;
entity.yRotO = 0.0f; entity.yRotO = 0.0f;
entity.setYHeadRot(0.0f); entity.setYHeadRot(0.0f);
entity.xo = 0.0f; entity.xo = 0.0f;
entity.xRotO = 0.0f; entity.xRotO = 0.0f;
if (perspective == 2)
matrix.mulPose(Axis.YP.rotationDegrees(180));
matrix.scale((10 - multiplier) * 0.08f, (10 - multiplier) * 0.08f, (10 - multiplier) * 0.08f); matrix.scale((10 - multiplier) * 0.08f, (10 - multiplier) * 0.08f, (10 - multiplier) * 0.08f);
matrix.translate(0.0, height / 2 + -(height / 2) + 1, width - 0.1 < 0.7 ? width - 0.1 + (0.7 - (width - 0.1)) : width - 0.1); 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) if (pose == Pose.SWIMMING || pose == Pose.FALL_FLYING)
{ {
matrix.mulPose(Axis.XN.rotationDegrees(90)); matrix.mulPose(Axis.XN.rotationDegrees(180));
matrix.translate(0, -0.2 * height, 0); matrix.translate(0, 0.2 * height - 2, -0.5);
if (pose == Pose.FALL_FLYING)
matrix.translate(0, 0, 0.2);
} }
if(Constants.CLIENT_CONFIG.rotateEntitiesSideways)
matrix.mulPose(Axis.YP.rotationDegrees(90));
} }
@ -228,18 +225,64 @@ public class CarryRenderHelper
matrix.scale((float) scale.x, (float) scale.y, (float) scale.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) public static void renderBakedModel(ItemStack stack, PoseStack matrix, MultiBufferSource buffer, int light, BakedModel model)
{ {
ItemStackRenderState state = new ItemStackRenderState();
try { 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(); 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); renderer.render(stack, ItemDisplayContext.NONE, false, matrix, buffer, light, OverlayTexture.NO_OVERLAY, model);
} }
catch (Exception e) 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) public static BlockState getRenderState(Player player)
{ {
@ -250,7 +293,7 @@ public class CarryRenderHelper
ScriptRender render = carry.getActiveScript().get().scriptRender(); ScriptRender render = carry.getActiveScript().get().scriptRender();
if(render.renderNameBlock().isPresent()) if(render.renderNameBlock().isPresent())
{ {
state = BuiltInRegistries.BLOCK.get(render.renderNameBlock().get()).defaultBlockState(); state = BuiltInRegistries.BLOCK.get(render.renderNameBlock().get()).get().value().defaultBlockState();
} }
} }
@ -265,16 +308,20 @@ public class CarryRenderHelper
return state; return state;
} }
/*
@Deprecated
public static BakedModel getRenderBlock(Player player) public static BakedModel getRenderBlock(Player player)
{ {
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
ItemRenderer renderer = Minecraft.getInstance().getItemRenderer(); ItemRenderer renderer = Minecraft.getInstance().getItemRenderer();
Minecraft.getInstance().getModelManager().specialBlockModelRenderer().get().
BlockState state = getRenderState(player); BlockState state = getRenderState(player);
BakedModel model = Minecraft.getInstance().getBlockRenderer().getBlockModel(state); BakedModel model = Minecraft.getInstance().getBlockRenderer().getBlockModel(state);
if(state.getRenderShape() != RenderShape.MODEL || model.isCustomRenderer() || model.getQuads(state, null, RandomSource.create()).size() <= 0) { if(state.getRenderShape() != RenderShape.MODEL || model.isCustomRenderer() || model.getQuads(state, null, RandomSource.create()).size() <= 0) {
ItemStack stack = new ItemStack(state.getBlock()); ItemStack stack = new ItemStack(state.getBlock());
model = renderer.getModel(stack, player.level, player, 0); model = renderer.getModel(stack, player.level(), player, 0);
} }
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt()); Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt());
@ -282,26 +329,29 @@ public class CarryRenderHelper
{ {
var renderObj = ov.get().getRenderObject(); var renderObj = ov.get().getRenderObject();
if(renderObj.left().isPresent()) if(renderObj.left().isPresent())
model = renderer.getModel(renderObj.left().get(), player.level, player, 0); model = renderer.getModel(renderObj.left().get(), player.level(), player, 0);
} }
return model; return model;
} }
*/
public static Entity getRenderEntity(Player player) public static Entity getRenderEntity(Player player)
{ {
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
Entity entity = carry.getEntity(player.level); Entity entity = carry.getEntity(player.level());
if(carry.getActiveScript().isPresent()) if(carry.getActiveScript().isPresent())
{ {
CarryOnScript script = carry.getActiveScript().get(); CarryOnScript script = carry.getActiveScript().get();
ScriptRender render = script.scriptRender(); ScriptRender render = script.scriptRender();
if(render.renderNameEntity().isPresent()) if(render.renderNameEntity().isPresent())
entity = BuiltInRegistries.ENTITY_TYPE.get(render.renderNameEntity().get()).create(player.level); entity = BuiltInRegistries.ENTITY_TYPE.get(render.renderNameEntity().get()).get().value().create(player.level(), EntitySpawnReason.EVENT);
if(render.renderNBT().isPresent()) if(render.renderNBT().isPresent()) {
entity.load(render.renderNBT().get()); ValueInput input = TagValueInput.create(new ProblemReporter.ScopedCollector(Constants.LOG), player.registryAccess(), render.renderNBT().get());
entity.load(input);
}
} }
return entity; return entity;
@ -313,7 +363,7 @@ public class CarryRenderHelper
if(carry.isCarrying(CarryType.BLOCK)) if(carry.isCarrying(CarryType.BLOCK))
{ {
BlockState state = getRenderState(player); BlockState state = getRenderState(player);
VoxelShape shape = state.getShape(player.level, player.blockPosition()); VoxelShape shape = state.getShape(player.level(), player.blockPosition());
if(shape == null || shape.isEmpty()) if(shape == null || shape.isEmpty())
return 1f; return 1f;
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt()); Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt());
@ -329,7 +379,10 @@ public class CarryRenderHelper
else if(carry.isCarrying(CarryType.ENTITY)) else if(carry.isCarrying(CarryType.ENTITY))
{ {
Entity entity = getRenderEntity(player); Entity entity = getRenderEntity(player);
return entity.getBbWidth(); float w = entity.getBbWidth();
if (Constants.CLIENT_CONFIG.rotateEntitiesSideways)
return w - (w*w) * 0.35f;
return w * 0.9f;
} }
else else
return 1f; return 1f;
@ -341,7 +394,7 @@ public class CarryRenderHelper
if(carry.isCarrying(CarryType.BLOCK)) if(carry.isCarrying(CarryType.BLOCK))
{ {
BlockState state = getRenderState(player); BlockState state = getRenderState(player);
VoxelShape shape = state.getShape(player.level, player.blockPosition()); VoxelShape shape = state.getShape(player.level(), player.blockPosition());
if(shape == null || shape.isEmpty()) if(shape == null || shape.isEmpty())
return 1f; return 1f;
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt()); Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt());
@ -387,7 +440,7 @@ public class CarryRenderHelper
public static boolean isChest(Block block) public static boolean isChest(Block block)
{ {
return block == Blocks.CHEST || block == Blocks.ENDER_CHEST || block == Blocks.TRAPPED_CHEST; 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

@ -1,24 +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.common.carry; package tschipp.carryon.common.carry;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult; import com.mojang.serialization.DataResult;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.Tag; 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.AreaEffectCloud;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; 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.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.Constants;
import tschipp.carryon.common.scripting.CarryOnScript; import tschipp.carryon.common.scripting.CarryOnScript;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
public class CarryOnData { public class CarryOnData {
@ -27,30 +60,56 @@ public class CarryOnData {
private boolean keyPressed = false; private boolean keyPressed = false;
private CarryOnScript activeScript; private CarryOnScript activeScript;
private int selectedSlot = 0; 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) public CarryOnData(CompoundTag data)
{ {
if(data.contains("type")) if(data.contains("type"))
this.type = CarryType.valueOf(data.getString("type")); this.type = CarryType.valueOf(data.getStringOr("type", "INVALID"));
else else
this.type = CarryType.INVALID; this.type = CarryType.INVALID;
this.nbt = data; this.nbt = data;
if(data.contains("keyPressed")) this.keyPressed = data.getBooleanOr("keyPressed", false);
this.keyPressed = data.getBoolean("keyPressed");
if(data.contains("activeScript")) if(data.contains("activeScript"))
{ {
DataResult<CarryOnScript> res = CarryOnScript.CODEC.parse(NbtOps.INSTANCE, data.get("activeScript")); DataResult<CarryOnScript> res = CarryOnScript.CODEC.parse(NbtOps.INSTANCE, data.get("activeScript"));
this.activeScript = res.getOrThrow(false, (s) -> {throw new RuntimeException("Failed to decode activeScript during CarryOnData serialization: " + s);}); this.activeScript = res.getOrThrow((s) -> {throw new RuntimeException("Failed to decode activeScript during CarryOnData serialization: " + s);});
} }
if(data.contains("selected")) this.selectedSlot = data.getIntOr("selected", 0);
this.selectedSlot = data.getInt("selected");
} }
public CarryType getType()
{
return this.type;
}
public CompoundTag getNbt() public CompoundTag getNbt()
{ {
nbt.putString("type", type.toString()); nbt.putString("type", type.toString());
@ -58,7 +117,7 @@ public class CarryOnData {
if(activeScript != null) if(activeScript != null)
{ {
DataResult<Tag> res = CarryOnScript.CODEC.encodeStart(NbtOps.INSTANCE, activeScript); DataResult<Tag> res = CarryOnScript.CODEC.encodeStart(NbtOps.INSTANCE, activeScript);
Tag tag = res.getOrThrow(false, (s) -> {throw new RuntimeException("Failed to encode activeScript during CarryOnData serialization: " + s);}); Tag tag = res.getOrThrow((s) -> {throw new RuntimeException("Failed to encode activeScript during CarryOnData serialization: " + s);});
nbt.put("activeScript", tag); nbt.put("activeScript", tag);
} }
nbt.putInt("selected", this.selectedSlot); nbt.putInt("selected", this.selectedSlot);
@ -68,13 +127,13 @@ public class CarryOnData {
public CompoundTag getContentNbt() public CompoundTag getContentNbt()
{ {
if(type == CarryType.BLOCK && nbt.contains("block")) if(type == CarryType.BLOCK && nbt.contains("block"))
return nbt.getCompound("block"); return nbt.getCompoundOrEmpty("block");
else if(type == CarryType.ENTITY && nbt.contains("entity")) else if(type == CarryType.ENTITY && nbt.contains("entity"))
return nbt.getCompound("entity"); return nbt.getCompoundOrEmpty("entity");
return null; return null;
} }
public void setBlock(BlockState state, @Nullable BlockEntity tile) public void setBlock(BlockState state, @Nullable BlockEntity tile, ServerPlayer player, BlockPos pos)
{ {
this.type = CarryType.BLOCK; this.type = CarryType.BLOCK;
@ -86,7 +145,9 @@ public class CarryOnData {
if(tile != null) if(tile != null)
{ {
CompoundTag tileData = tile.saveWithId(); TagValueOutput output = TagValueOutput.createWithContext(problemReporter, player.registryAccess());
tile.saveWithId(output);
Tag tileData = output.buildResult();
nbt.put("tile", tileData); nbt.put("tile", tileData);
} }
} }
@ -96,11 +157,11 @@ public class CarryOnData {
if(this.type != CarryType.BLOCK) if(this.type != CarryType.BLOCK)
throw new IllegalStateException("Called getBlock on data that contained " + this.type); throw new IllegalStateException("Called getBlock on data that contained " + this.type);
return NbtUtils.readBlockState(BuiltInRegistries.BLOCK.asLookup(), nbt.getCompound("block")); return NbtUtils.readBlockState(BuiltInRegistries.BLOCK, nbt.getCompoundOrEmpty("block"));
} }
@Nullable @Nullable
public BlockEntity getBlockEntity(BlockPos pos) public BlockEntity getBlockEntity(BlockPos pos, HolderLookup.Provider lookup)
{ {
if(this.type != CarryType.BLOCK) if(this.type != CarryType.BLOCK)
throw new IllegalStateException("Called getBlockEntity on data that contained " + this.type); throw new IllegalStateException("Called getBlockEntity on data that contained " + this.type);
@ -108,14 +169,15 @@ public class CarryOnData {
if(!nbt.contains("tile")) if(!nbt.contains("tile"))
return null; return null;
return BlockEntity.loadStatic(pos, this.getBlock(), nbt.getCompound("tile")); return BlockEntity.loadStatic(pos, this.getBlock(), nbt.getCompoundOrEmpty("tile"), lookup);
} }
public void setEntity(Entity entity) public void setEntity(Entity entity)
{ {
this.type = CarryType.ENTITY; this.type = CarryType.ENTITY;
CompoundTag entityData = new CompoundTag(); TagValueOutput output = TagValueOutput.createWithContext(new ProblemReporter.ScopedCollector(Constants.LOG), entity.registryAccess());
entity.save(entityData); entity.save(output);
Tag entityData = output.buildResult();
nbt.put("entity", entityData); nbt.put("entity", entityData);
} }
@ -124,7 +186,8 @@ public class CarryOnData {
if(this.type != CarryType.ENTITY) if(this.type != CarryType.ENTITY)
throw new IllegalStateException("Called getEntity on data that contained " + this.type); throw new IllegalStateException("Called getEntity on data that contained " + this.type);
var optionalEntity = EntityType.create(nbt.getCompound("entity"), level); ValueInput in = TagValueInput.create(problemReporter, level.registryAccess(), nbt.getCompoundOrEmpty("entity"));
var optionalEntity = EntityType.create(in, level, EntitySpawnReason.BUCKET);
if(optionalEntity.isPresent()) if(optionalEntity.isPresent())
return optionalEntity.get(); return optionalEntity.get();
@ -145,8 +208,20 @@ public class CarryOnData {
this.activeScript = script; this.activeScript = script;
} }
public void setCarryingPlayer() { public void setCarryingPlayer(Player player)
{
this.type = CarryType.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() public boolean isCarrying()
@ -181,13 +256,20 @@ public class CarryOnData {
this.activeScript = null; this.activeScript = null;
} }
public CarryOnData clone() {
return new CarryOnData(nbt.copy());
}
public int getTick() public int getTick()
{ {
if(!this.nbt.contains("tick")) return this.nbt.getIntOr("tick", -1);
return -1;
return this.nbt.getInt("tick");
} }
public void setTick(int tick) {
this.nbt.putInt("tick", tick);
}
public enum CarryType { public enum CarryType {
BLOCK, BLOCK,
ENTITY, ENTITY,

View File

@ -1,28 +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; package tschipp.carryon.common.carry;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import tschipp.carryon.platform.Services;
public class CarryOnDataManager { public class CarryOnDataManager {
public static final EntityDataAccessor<CompoundTag> CARRY_DATA_KEY = SynchedEntityData.defineId(Player.class, EntityDataSerializers.COMPOUND_TAG);
public static CarryOnData getCarryData(Player player) public static CarryOnData getCarryData(Player player)
{ {
CompoundTag data = player.getEntityData().get(CARRY_DATA_KEY); return Services.PLATFORM.getCarryData(player);
return new CarryOnData(data.copy());
} }
public static void setCarryData(Player player, CarryOnData data) public static void setCarryData(Player player, CarryOnData data)
{ {
data.setSelected(player.getInventory().selected); data.setSelected(player.getInventory().getSelectedSlot());
CompoundTag nbt = data.getNbt(); data.setTick(player.tickCount);
nbt.putInt("tick", player.tickCount); Services.PLATFORM.setCarryData(player, data);
player.getEntityData().set(CARRY_DATA_KEY, nbt);
} }
} }

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.common.carry;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -5,26 +25,30 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource; import net.minecraft.sounds.SoundSource;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.AgeableMob; import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.Entity; import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.Entity.RemovalReason; import net.minecraft.world.entity.Entity.RemovalReason;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.entity.TamableAnimal;
import net.minecraft.world.entity.animal.Animal; import net.minecraft.world.entity.animal.Animal;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.GameType; import net.minecraft.world.level.GameType;
import net.minecraft.world.level.Level; 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.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; 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 net.minecraft.world.phys.Vec3;
import tschipp.carryon.CarryOnCommon;
import tschipp.carryon.Constants; import tschipp.carryon.Constants;
import tschipp.carryon.common.config.ListHandler; import tschipp.carryon.common.config.ListHandler;
import tschipp.carryon.common.pickupcondition.PickupCondition; import tschipp.carryon.common.pickupcondition.PickupCondition;
import tschipp.carryon.common.pickupcondition.PickupConditionHandler; import tschipp.carryon.common.pickupcondition.PickupConditionHandler;
import tschipp.carryon.common.scripting.CarryOnScript; import tschipp.carryon.common.scripting.CarryOnScript;
import tschipp.carryon.common.scripting.ScriptManager; import tschipp.carryon.common.scripting.ScriptManager;
import tschipp.carryon.networking.clientbound.ClientboundStartRidingPacket; import tschipp.carryon.networking.clientbound.ClientboundStartRidingOtherPlayerPacket;
import tschipp.carryon.platform.Services; import tschipp.carryon.platform.Services;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -72,16 +96,26 @@ public class PickupHandler {
BlockEntity blockEntity = level.getBlockEntity(pos); BlockEntity blockEntity = level.getBlockEntity(pos);
BlockState state = level.getBlockState(pos); BlockState state = level.getBlockState(pos);
CompoundTag nbt = null; CompoundTag nbt = null;
if(blockEntity != null) if(blockEntity != null) {
nbt = blockEntity.saveWithId(); 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())) if(!ListHandler.isPermitted(state.getBlock()))
return false; return false;
if(state.getDestroySpeed(level, pos) == -1 && !player.isCreative() && !Constants.COMMON_CONFIG.settings.pickupUnbreakableBlocks) // Reject pickup of Double blocks, if they use the vanilla property
if(hasPropertyType(state, DoorBlock.HALF))
return false; return false;
if(blockEntity == null && !Constants.COMMON_CONFIG.settings.pickupAllBlocks) 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; return false;
//Check if TE is locked //Check if TE is locked
@ -102,7 +136,6 @@ public class PickupHandler {
if(!doPickup) if(!doPickup)
return false; return false;
Optional<CarryOnScript> result = ScriptManager.inspectBlock(state, level, pos, nbt);
if(result.isPresent()) if(result.isPresent())
{ {
CarryOnScript script = result.get(); CarryOnScript script = result.get();
@ -113,10 +146,10 @@ public class PickupHandler {
String cmd = script.scriptEffects().commandInit(); String cmd = script.scriptEffects().commandInit();
if(!cmd.isEmpty()) if(!cmd.isEmpty())
player.getServer().getCommands().performPrefixedCommand(player.getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().getName() + " run " + cmd); player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
} }
carry.setBlock(state, blockEntity); carry.setBlock(state, blockEntity, player, pos);
level.removeBlockEntity(pos); level.removeBlockEntity(pos);
level.removeBlock(pos, false); level.removeBlock(pos, false);
@ -124,6 +157,8 @@ public class PickupHandler {
CarryOnDataManager.setCarryData(player, carry); CarryOnDataManager.setCarryData(player, carry);
level.playSound(null, pos, state.getSoundType().getHitSound(), SoundSource.BLOCKS, 1.0f, 0.5f); level.playSound(null, pos, state.getSoundType().getHitSound(), SoundSource.BLOCKS, 1.0f, 0.5f);
player.swing(InteractionHand.MAIN_HAND, true); 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; return true;
} }
@ -142,23 +177,29 @@ public class PickupHandler {
if (entity instanceof TamableAnimal tame) if (entity instanceof TamableAnimal tame)
{ {
UUID owner = tame.getOwnerUUID(); EntityReference<LivingEntity> ref = tame.getOwnerReference();
UUID playerID = player.getGameProfile().getId(); if (ref != null) {
if (owner != null && !owner.equals(playerID)) UUID owner = ref.getUUID();
return false; 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)) if(!ListHandler.isPermitted(entity))
{ {
//We can pick up baby animals even if the grown up animal is blacklisted. //We can pick up baby animals even if the grown up animal is blacklisted.
if(!(entity instanceof AgeableMob ageableMob && Constants.COMMON_CONFIG.settings.allowBabies && (ageableMob.getAge() < 0 || ageableMob.isBaby()))) if(!overrideChecks && (!(entity instanceof AgeableMob ageableMob && Constants.COMMON_CONFIG.settings.allowBabies && (ageableMob.getAge() < 0 || ageableMob.isBaby()))))
return false; return false;
} }
//Non-Creative only guards //Non-Creative only guards
if(!player.isCreative()) if(!player.isCreative())
{ {
if(!Constants.COMMON_CONFIG.settings.pickupHostileMobs && entity.getType().getCategory() == MobCategory.MONSTER) if(!overrideChecks && (!Constants.COMMON_CONFIG.settings.pickupHostileMobs && entity.getType().getCategory() == MobCategory.MONSTER))
return false; return false;
if(Constants.COMMON_CONFIG.settings.maxEntityHeight < entity.getBbHeight() || Constants.COMMON_CONFIG.settings.maxEntityWidth < entity.getBbWidth()) if(Constants.COMMON_CONFIG.settings.maxEntityHeight < entity.getBbHeight() || Constants.COMMON_CONFIG.settings.maxEntityWidth < entity.getBbWidth())
@ -172,13 +213,12 @@ public class PickupHandler {
return false; return false;
} }
boolean doPickup = pickupCallback == null ? true : pickupCallback.apply(entity); boolean doPickup = pickupCallback == null || pickupCallback.apply(entity);
if(!doPickup) if(!doPickup)
return false; return false;
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
Optional<CarryOnScript> result = ScriptManager.inspectEntity(entity);
if(result.isPresent()) if(result.isPresent())
{ {
CarryOnScript script = result.get(); CarryOnScript script = result.get();
@ -201,15 +241,17 @@ public class PickupHandler {
if (result.isPresent()) { if (result.isPresent()) {
String cmd = result.get().scriptEffects().commandInit(); String cmd = result.get().scriptEffects().commandInit();
if (!cmd.isEmpty()) if (!cmd.isEmpty())
player.getServer().getCommands().performPrefixedCommand(player.getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().getName() + " run " + cmd); player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
} }
otherPlayer.startRiding(player); otherPlayer.startRiding(player, true, false);
Services.PLATFORM.sendPacketToPlayer(Constants.PACKET_ID_START_RIDING, new ClientboundStartRidingPacket(otherPlayer.getId(), true), player); Services.PLATFORM.sendPacketToAllPlayers(Constants.PACKET_ID_START_RIDING_OTHER, new ClientboundStartRidingOtherPlayerPacket(player.getId(), otherPlayer.getId(), true), player.level());
carry.setCarryingPlayer(); carry.setCarryingPlayer(otherPlayer);
player.swing(InteractionHand.MAIN_HAND, true); player.swing(InteractionHand.MAIN_HAND, true);
player.level.playSound(null, player.getOnPos(), SoundEvents.ARMOR_EQUIP_GENERIC, SoundSource.AMBIENT, 1.0f, 0.5f); player.level().playSound(null, player.getOnPos(), SoundEvents.ARMOR_EQUIP_GENERIC.value(), SoundSource.AMBIENT, 1.0f, 0.5f);
CarryOnDataManager.setCarryData(player, carry); 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; return true;
} }
@ -217,23 +259,33 @@ public class PickupHandler {
entity.ejectPassengers(); entity.ejectPassengers();
entity.stopRiding(); entity.stopRiding();
if (entity instanceof Animal animal) { if (entity instanceof Animal animal) {
animal.dropLeash(true, true); animal.dropLeash();
} }
if(result.isPresent()) if(result.isPresent())
{ {
String cmd = result.get().scriptEffects().commandInit(); String cmd = result.get().scriptEffects().commandInit();
if(!cmd.isEmpty()) if(!cmd.isEmpty())
player.getServer().getCommands().performPrefixedCommand(player.getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().getName() + " run " + cmd); player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
} }
carry.setEntity(entity); carry.setEntity(entity);
entity.remove(RemovalReason.UNLOADED_WITH_PLAYER); entity.remove(RemovalReason.UNLOADED_WITH_PLAYER);
player.level.playSound(null, player.getOnPos(), SoundEvents.ARMOR_EQUIP_GENERIC, SoundSource.AMBIENT, 1.0f, 0.5f); player.level().playSound(null, player.getOnPos(), SoundEvents.ARMOR_EQUIP_GENERIC.value(), SoundSource.AMBIENT, 1.0f, 0.5f);
CarryOnDataManager.setCarryData(player, carry); CarryOnDataManager.setCarryData(player, carry);
player.swing(InteractionHand.MAIN_HAND, true); 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; 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

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.common.carry;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -6,19 +26,19 @@ import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource; import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.animal.horse.Horse; import net.minecraft.world.entity.animal.equine.Horse;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; 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.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.block.state.properties.Property; 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.BlockHitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.CollisionContext;
@ -26,6 +46,8 @@ import tschipp.carryon.Constants;
import tschipp.carryon.common.carry.CarryOnData.CarryType; import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.config.ListHandler; import tschipp.carryon.common.config.ListHandler;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptEffects; import tschipp.carryon.common.scripting.CarryOnScript.ScriptEffects;
import tschipp.carryon.networking.clientbound.ClientboundStartRidingOtherPlayerPacket;
import tschipp.carryon.platform.Services;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
@ -45,7 +67,7 @@ public class PlacementHandler
if (player.tickCount == carry.getTick()) if (player.tickCount == carry.getTick())
return false; return false;
Level level = player.getLevel(); Level level = player.level();
BlockState state = carry.getBlock(); BlockState state = carry.getBlock();
BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos)); BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos));
@ -55,7 +77,7 @@ public class PlacementHandler
context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos)); context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos));
BlockEntity blockEntity = carry.getBlockEntity(pos); BlockEntity blockEntity = carry.getBlockEntity(pos, level.registryAccess());
state = getPlacementState(state, player, context, pos); state = getPlacementState(state, player, context, pos);
@ -70,22 +92,29 @@ public class PlacementHandler
if (!doPlace) if (!doPlace)
return false; return false;
if(level.isOutsideBuildHeight(pos))
return false;
if (carry.getActiveScript().isPresent()) { if (carry.getActiveScript().isPresent()) {
ScriptEffects effects = carry.getActiveScript().get().scriptEffects(); ScriptEffects effects = carry.getActiveScript().get().scriptEffects();
String cmd = effects.commandPlace(); String cmd = effects.commandPlace();
if (!cmd.isEmpty()) if (!cmd.isEmpty())
player.getServer().getCommands().performPrefixedCommand(player.getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().getName() + " run " + cmd); player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
} }
level.setBlockAndUpdate(pos, state); level.setBlockAndUpdate(pos, state);
if (blockEntity != null) if (blockEntity != null) {
blockEntity.setBlockState(state);
level.setBlockEntity(blockEntity); level.setBlockEntity(blockEntity);
}
level.updateNeighborsAt(pos.relative(Direction.DOWN), level.getBlockState(pos.relative(Direction.DOWN)).getBlock()); level.updateNeighborsAt(pos.relative(Direction.DOWN), level.getBlockState(pos.relative(Direction.DOWN)).getBlock());
carry.clear(); carry.clear();
CarryOnDataManager.setCarryData(player, carry); CarryOnDataManager.setCarryData(player, carry);
player.playSound(state.getSoundType().getPlaceSound(), 1.0f, 0.5f); player.playSound(state.getSoundType().getPlaceSound(), 1.0f, 0.5f);
level.playSound(null, pos, state.getSoundType().getPlaceSound(), SoundSource.BLOCKS, 1.0f, 0.5f); level.playSound(null, pos, state.getSoundType().getPlaceSound(), SoundSource.BLOCKS, 1.0f, 0.5f);
player.swing(InteractionHand.MAIN_HAND, true); player.swing(InteractionHand.MAIN_HAND, true);
player.removeEffect(MobEffects.SLOWNESS);
return true; return true;
} }
@ -96,7 +125,7 @@ public class PlacementHandler
placementState = state; placementState = state;
for (var prop : placementState.getProperties()) { for (var prop : placementState.getProperties()) {
if (prop instanceof DirectionProperty) if (prop.getValueClass() == Direction.class)
state = updateProperty(state, placementState, prop); state = updateProperty(state, placementState, prop);
if (prop.getValueClass() == Direction.Axis.class) if (prop.getValueClass() == Direction.Axis.class)
state = updateProperty(state, placementState, prop); state = updateProperty(state, placementState, prop);
@ -106,7 +135,7 @@ public class PlacementHandler
} }
} }
BlockState updatedState = Block.updateFromNeighbourShapes(state, player.level, pos); BlockState updatedState = Block.updateFromNeighbourShapes(state, player.level(), pos);
if (updatedState.getBlock() == state.getBlock()) if (updatedState.getBlock() == state.getBlock())
state = updatedState; state = updatedState;
@ -132,23 +161,30 @@ public class PlacementHandler
if (player.tickCount == carry.getTick()) if (player.tickCount == carry.getTick())
return false; return false;
Level level = player.getLevel(); Level level = player.level();
BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos)); BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos));
if (!level.getBlockState(pos).canBeReplaced(context)) if (!level.getBlockState(pos).canBeReplaced(context)) {
pos = pos.relative(facing); 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); Vec3 placementPos = Vec3.atBottomCenterOf(pos);
if (carry.isCarrying(CarryType.PLAYER)) { if (carry.isCarrying(CarryType.PLAYER)) {
Entity otherPlayer = player.getFirstPassenger(); Entity otherPlayer = carry.getCarryingPlayer(level);
player.ejectPassengers(); player.ejectPassengers();
Services.PLATFORM.sendPacketToAllPlayers(Constants.PACKET_ID_START_RIDING_OTHER, new ClientboundStartRidingOtherPlayerPacket(player.getId(), otherPlayer.getId(), false), player.level());
carry.clear(); carry.clear();
CarryOnDataManager.setCarryData(player, carry); CarryOnDataManager.setCarryData(player, carry);
if (otherPlayer == null) otherPlayer.teleportTo(placementPos.x, placementPos.y, placementPos.z);
return true;
otherPlayer.teleportTo(placementPos.x, placementPos.y, placementPos.z);
player.swing(InteractionHand.MAIN_HAND, true); player.swing(InteractionHand.MAIN_HAND, true);
player.removeEffect(MobEffects.SLOWNESS);
return true; return true;
} }
@ -163,7 +199,7 @@ public class PlacementHandler
ScriptEffects effects = carry.getActiveScript().get().scriptEffects(); ScriptEffects effects = carry.getActiveScript().get().scriptEffects();
String cmd = effects.commandPlace(); String cmd = effects.commandPlace();
if (!cmd.isEmpty()) if (!cmd.isEmpty())
player.getServer().getCommands().performPrefixedCommand(player.getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().getName() + " run " + cmd); player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
} }
level.addFreshEntity(entity); level.addFreshEntity(entity);
@ -173,6 +209,7 @@ public class PlacementHandler
player.swing(InteractionHand.MAIN_HAND, true); player.swing(InteractionHand.MAIN_HAND, true);
carry.clear(); carry.clear();
CarryOnDataManager.setCarryData(player, carry); CarryOnDataManager.setCarryData(player, carry);
player.removeEffect(MobEffects.SLOWNESS);
return true; return true;
} }
@ -185,13 +222,15 @@ public class PlacementHandler
if (!carry.isCarrying(CarryType.ENTITY) && !carry.isCarrying(CarryType.PLAYER)) if (!carry.isCarrying(CarryType.ENTITY) && !carry.isCarrying(CarryType.PLAYER))
return; return;
Level level = player.level; Level level = player.level();
Entity entityHeld; Entity entityHeld;
if (carry.isCarrying(CarryType.ENTITY)) if (carry.isCarrying(CarryType.ENTITY))
entityHeld = carry.getEntity(level); entityHeld = carry.getEntity(level);
else else
entityHeld = player.getFirstPassenger(); entityHeld = player.getFirstPassenger();
if(entityHeld == null)
return;
double sizeHeldEntity = entityHeld.getBbHeight() * entityHeld.getBbWidth(); double sizeHeldEntity = entityHeld.getBbHeight() * entityHeld.getBbWidth();
double distance = entityClicked.blockPosition().distSqr(player.blockPosition()); double distance = entityClicked.blockPosition().distSqr(player.blockPosition());
@ -205,7 +244,7 @@ public class PlacementHandler
if (ListHandler.isStackingPermitted(topEntity)) { if (ListHandler.isStackingPermitted(topEntity)) {
double sizeEntity = topEntity.getBbHeight() * topEntity.getBbWidth(); double sizeEntity = topEntity.getBbHeight() * topEntity.getBbWidth();
if (Constants.COMMON_CONFIG.settings.entitySizeMattersStacking && sizeHeldEntity <= sizeEntity || !Constants.COMMON_CONFIG.settings.entitySizeMattersStacking) { if (!Constants.COMMON_CONFIG.settings.entitySizeMattersStacking || sizeHeldEntity <= sizeEntity) {
if (topEntity instanceof Horse horse) if (topEntity instanceof Horse horse)
horse.setTamed(true); horse.setTamed(true);
@ -218,26 +257,27 @@ public class PlacementHandler
level.addFreshEntity(entityHeld); level.addFreshEntity(entityHeld);
entityHeld.teleportTo(tempX, tempY, tempZ); entityHeld.teleportTo(tempX, tempY, tempZ);
} }
entityHeld.startRiding(topEntity, false); entityHeld.startRiding(topEntity, false,false);
} else { } else {
if (carry.isCarrying(CarryType.ENTITY)) { if (carry.isCarrying(CarryType.ENTITY)) {
entityHeld.setPos(entityClicked.getX(), entityClicked.getY(), entityClicked.getZ()); entityHeld.setPos(entityClicked.getX(), entityClicked.getY(), entityClicked.getZ());
level.addFreshEntity(entityHeld); level.addFreshEntity(entityHeld);
} }
entityHeld.startRiding(topEntity, false); entityHeld.startRiding(topEntity, false,false);
} }
if (carry.getActiveScript().isPresent()) { if (carry.getActiveScript().isPresent()) {
ScriptEffects effects = carry.getActiveScript().get().scriptEffects(); ScriptEffects effects = carry.getActiveScript().get().scriptEffects();
String cmd = effects.commandPlace(); String cmd = effects.commandPlace();
if (!cmd.isEmpty()) if (!cmd.isEmpty())
player.getServer().getCommands().performPrefixedCommand(player.getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().getName() + " run " + cmd); player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
} }
player.swing(InteractionHand.MAIN_HAND, true); player.swing(InteractionHand.MAIN_HAND, true);
carry.clear(); carry.clear();
CarryOnDataManager.setCarryData(player, carry); CarryOnDataManager.setCarryData(player, carry);
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.HORSE_SADDLE, SoundSource.PLAYERS, 0.5F, 1.5F); level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.HORSE_SADDLE, SoundSource.PLAYERS, 0.5F, 1.5F);
player.removeEffect(MobEffects.SLOWNESS);
} else { } else {
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.LAVA_POP, SoundSource.PLAYERS, 0.5F, 0.5F); level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.LAVA_POP, SoundSource.PLAYERS, 0.5F, 0.5F);
} }
@ -250,10 +290,10 @@ public class PlacementHandler
public static void placeCarriedOnDeath(ServerPlayer oldPlayer, ServerPlayer newPlayer, boolean died) public static void placeCarriedOnDeath(ServerPlayer oldPlayer, ServerPlayer newPlayer, boolean died)
{ {
CarryOnData carry = CarryOnDataManager.getCarryData(oldPlayer); CarryOnData carry = CarryOnDataManager.getCarryData(oldPlayer);
if (oldPlayer.level.getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || !died) { if (oldPlayer.level().getGameRules().get(GameRules.KEEP_INVENTORY) || !died) {
if (!carry.isCarrying(CarryType.PLAYER)) { if (!carry.isCarrying(CarryType.PLAYER)) {
CarryOnDataManager.setCarryData(newPlayer, carry); CarryOnDataManager.setCarryData(newPlayer, carry);
newPlayer.getInventory().selected = oldPlayer.getInventory().selected; newPlayer.getInventory().setSelectedSlot(oldPlayer.getInventory().getSelectedSlot());
return; return;
} }
} }
@ -265,22 +305,23 @@ public class PlacementHandler
{ {
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
if (carry.isCarrying(CarryType.ENTITY)) { if (carry.isCarrying(CarryType.ENTITY)) {
Entity entity = carry.getEntity(player.level); Entity entity = carry.getEntity(player.level());
entity.setPos(player.position()); entity.setPos(player.position());
player.level.addFreshEntity(entity); player.level().addFreshEntity(entity);
} else if (carry.isCarrying(CarryType.BLOCK)) { } 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())); 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()); BlockState state = getPlacementState(carry.getBlock(), player, context, player.blockPosition());
BlockPos pos = getDeathPlacementPos(state, player); BlockPos pos = getDeathPlacementPos(state, player);
BlockEntity blockEntity = carry.getBlockEntity(pos); BlockEntity blockEntity = carry.getBlockEntity(pos, player.level().registryAccess());
player.level.setBlock(pos, state, 3); player.level().setBlock(pos, state, 3);
if (blockEntity != null) if (blockEntity != null)
player.level.setBlockEntity(blockEntity); player.level().setBlockEntity(blockEntity);
} else if (carry.isCarrying(CarryType.PLAYER)) { } else if (carry.isCarrying(CarryType.PLAYER)) {
player.ejectPassengers(); player.ejectPassengers();
} }
carry.clear(); carry.clear();
CarryOnDataManager.setCarryData(player, carry); CarryOnDataManager.setCarryData(player, carry);
player.removeEffect(MobEffects.SLOWNESS);
} }
private static BlockPos getDeathPlacementPos(BlockState state, ServerPlayer player) private static BlockPos getDeathPlacementPos(BlockState state, ServerPlayer player)
@ -307,7 +348,7 @@ public class PlacementHandler
for(BlockPos potential : potentialPositions) for(BlockPos potential : potentialPositions)
{ {
BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(Vec3.atCenterOf(potential), Direction.DOWN, potential)); 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)); boolean canPlace = state.canSurvive(player.level(), potential) && player.level().getBlockState(potential).canBeReplaced(context) && player.level().isUnobstructed(state, potential, CollisionContext.of(player));
if (canPlace) if (canPlace)
return potential; return potential;

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

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.common.command;
import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.CommandDispatcher;
@ -8,6 +28,8 @@ import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.EntityArgument; import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer; 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.entity.Entity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import tschipp.carryon.Constants; import tschipp.carryon.Constants;
@ -34,11 +56,11 @@ public class CommandCarryOn
.then(Commands.literal("clear").executes(cmd -> handleClear(cmd.getSource(), Collections.singleton(cmd.getSource().getPlayerOrException())))) .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.hasPermission(2)).executes(cmd -> handleClear(cmd.getSource(), EntityArgument.getPlayers(cmd, "target"))))) .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.hasPermission(2)).executes(cmd -> handlePlace(cmd.getSource(), Collections.singleton(cmd.getSource().getPlayerOrException())))) .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.hasPermission(2)).executes(cmd -> handlePlace(cmd.getSource(), EntityArgument.getPlayers(cmd, "target"))))) .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")))))
; ;
@ -75,7 +97,7 @@ public class CommandCarryOn
} }
else if (carry.isCarrying(CarryType.ENTITY)) else if (carry.isCarrying(CarryType.ENTITY))
{ {
Entity entity = carry.getEntity(player.level); Entity entity = carry.getEntity(player.level());
log(source,"Entity: " + entity); log(source,"Entity: " + entity);
log(source,"Entity Name: " + entity.getType()); log(source,"Entity Name: " + entity.getType());
log(source,"NBT: " + carry.getNbt()); log(source,"NBT: " + carry.getNbt());
@ -112,11 +134,14 @@ public class CommandCarryOn
cleared++; cleared++;
} }
int finalCleared = cleared;
if (cleared != 1) if (cleared != 1) {
source.sendSuccess(Component.literal("Cleared " + cleared + " Items!"), true); source.sendSuccess(() -> Component.literal("Cleared " + finalCleared + " Items!"), true);
else }
source.sendSuccess(Component.literal("Cleared " + cleared + " Item!"), true); else {
source.sendSuccess(() -> Component.literal("Cleared " + finalCleared + " Item!"), true);
}
return 1; return 1;
} }
@ -129,18 +154,20 @@ public class CommandCarryOn
PlacementHandler.placeCarried(player); PlacementHandler.placeCarried(player);
cleared++; cleared++;
} }
int finalCleared = cleared;
if (cleared != 1) if (cleared != 1) {
source.sendSuccess(Component.literal("Placed " + cleared + " Items!"), true); source.sendSuccess(() -> Component.literal("Placed " + finalCleared + " Items!"), true);
}
else else
source.sendSuccess(Component.literal("Placed " + cleared + " Item!"), true); source.sendSuccess(() -> Component.literal("Placed " + finalCleared + " Item!"), true);
return 1; return 1;
} }
private static void log(CommandSourceStack source, String toLog) private static void log(CommandSourceStack source, String toLog)
{ {
source.sendSuccess(Component.literal(toLog), true); source.sendSuccess(() -> Component.literal(toLog), true);
Constants.LOG.info(toLog); Constants.LOG.info(toLog);
} }
} }

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.common.config;
import tschipp.carryon.config.PropertyType; import tschipp.carryon.config.PropertyType;
@ -18,7 +38,7 @@ public class CarryConfig
) )
public Settings settings = new Settings(); public Settings settings = new Settings();
@Category("settings") @Category(value="settings", translation = "carryon.category.settings")
public static class Settings public static class Settings
{ {
@Property( @Property(
@ -151,7 +171,8 @@ public class CarryConfig
@Property( @Property(
type = PropertyType.STRING_ARRAY, 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." 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 = { public String[] placementStateExceptions = {
"minecraft:chest[type]", "minecraft:chest[type]",
@ -184,24 +205,27 @@ public class CarryConfig
//Whitelist //Whitelist
public Whitelist whitelist = new Whitelist(); public Whitelist whitelist = new Whitelist();
@Category("whitelist") @Category(value="whitelist", translation = "carryon.category.whitelist")
public static class Whitelist public static class Whitelist
{ {
@Property( @Property(
type = PropertyType.STRING_ARRAY, type = PropertyType.STRING_ARRAY,
description = "Entities that CAN be picked up (useWhitelistEntities must be true)" 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 = {}; public String[] allowedEntities = {};
@Property( @Property(
type = PropertyType.STRING_ARRAY, type = PropertyType.STRING_ARRAY,
description = "Blocks that CAN be picked up (useWhitelistBlocks must be true)" 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 = {}; public String[] allowedBlocks = {};
@Property( @Property(
type = PropertyType.STRING_ARRAY, type = PropertyType.STRING_ARRAY,
description = "Entities that CAN have other entities stacked on top of them (useWhitelistStacking must be true)" 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 = {}; public String[] allowedStacking = {};
} }
@ -213,15 +237,17 @@ public class CarryConfig
) )
public Blacklist blacklist = new Blacklist(); public Blacklist blacklist = new Blacklist();
@Category("blacklist") @Category(value="blacklist", translation = "carryon.category.blacklist")
public static class Blacklist public static class Blacklist
{ {
@Property( @Property(
type = PropertyType.STRING_ARRAY, type = PropertyType.STRING_ARRAY,
description = "Blocks that cannot be picked up" 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 = { public String[] forbiddenTiles = {
"#forge:immovable", "#forge:relocation_not_supported", "minecraft:end_portal", "minecraft:piston_head", "#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:end_gateway", "minecraft:tall_grass", "minecraft:large_fern", "minecraft:peony",
"minecraft:rose_bush", "minecraft:lilac", "minecraft:sunflower", "minecraft:*_bed", "minecraft:rose_bush", "minecraft:lilac", "minecraft:sunflower", "minecraft:*_bed",
"minecraft:*_door", "minecraft:big_dripleaf_stem", "minecraft:waterlily", "minecraft:cake", "minecraft:*_door", "minecraft:big_dripleaf_stem", "minecraft:waterlily", "minecraft:cake",
@ -245,28 +271,48 @@ public class CarryConfig
"betterstorage:*", "practicallogistics2:*", "wearablebackpacks:*", "rftools:screen", "betterstorage:*", "practicallogistics2:*", "wearablebackpacks:*", "rftools:screen",
"rftools:creative_screen", "create:*", "magic_doorknob:*", "iceandfire:*", "ftbquests:*", "rftools:creative_screen", "create:*", "magic_doorknob:*", "iceandfire:*", "ftbquests:*",
"waystones:*", "contact:*", "framedblocks:*", "securitycraft:*", "forgemultipartcbe:*", "integrateddynamics:cable", "waystones:*", "contact:*", "framedblocks:*", "securitycraft:*", "forgemultipartcbe:*", "integrateddynamics:cable",
"mekanismgenerators:wind_generator" "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( @Property(
type = PropertyType.STRING_ARRAY, type = PropertyType.STRING_ARRAY,
description = "Entities that cannot be picked up" 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 = { public String[] forbiddenEntities = {
"minecraft:end_crystal", "minecraft:ender_dragon", "minecraft:ghast", "#c:capturing_not_supported", "#c:teleporting_not_supported",
"minecraft:shulker", "minecraft:leash_knot", "minecraft:armor_stand", "minecraft:end_crystal", "minecraft:ender_dragon", "minecraft:ghast", "minecraft:fireball", "minecraft:small_fireball", "minecraft:whither_skull",
"minecraft:item_frame", "minecraft:painting", "minecraft:shulker_bullet", "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:hamster", "animania:ferret*", "animania:hedgehog*", "animania:cart",
"animania:wagon", "mynko:*", "pixelmon:*", "mocreatures:*", "quark:totem", "vehicle:*", "animania:wagon", "mynko:*", "pixelmon:*", "mocreatures:*", "quark:totem", "vehicle:*",
"securitycraft:*", "taterzens:npc", "easy_npc:*" "securitycraft:*", "taterzens:npc", "easy_npc:*", "bodiesbodies:dead_body", "littletiles:*",
"connectiblechains:*", "cobblemon:*", "create:*", "swem:*", "toms_mobs:*"
}; };
@Property( @Property(
type = PropertyType.STRING_ARRAY, type = PropertyType.STRING_ARRAY,
description = "Entities that cannot have other entities stacked on top of them" 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 = { public String[] forbiddenStacking = {
"minecraft:horse" "minecraft:horse",
"minecraft:ender_dragon"
}; };
} }
@ -277,18 +323,20 @@ public class CarryConfig
) )
public CustomPickupConditions customPickupConditions = new CustomPickupConditions(); public CustomPickupConditions customPickupConditions = new CustomPickupConditions();
@Category("customPickupConditions") @Category(value="customPickupConditions", translation = "carryon.category.custompickupconditions")
public static class CustomPickupConditions public static class CustomPickupConditions
{ {
@Property( @Property(
type = PropertyType.STRING_ARRAY, type = PropertyType.STRING_ARRAY,
description = "Custom Pickup Conditions for Blocks" description = "Custom Pickup Conditions for Blocks",
validationRegex = "([a-zA-Z0-9_*\\-:]+(?:\\[[^\\]]*\\])?)\\(([\\w_]+)\\)"
) )
public String[] customPickupConditionsBlocks = {}; public String[] customPickupConditionsBlocks = {};
@Property( @Property(
type = PropertyType.STRING_ARRAY, type = PropertyType.STRING_ARRAY,
description = "Custom Pickup Conditions for Entities" description = "Custom Pickup Conditions for Entities",
validationRegex = "([a-zA-Z0-9_*\\-:]+(?:\\[[^\\]]*\\])?)\\(([\\w_]+)\\)"
) )
public String[] customPickupConditionsEntities = {}; public String[] customPickupConditionsEntities = {};
} }
@ -304,6 +352,12 @@ public class CarryConfig
) )
public boolean facePlayer = false; public boolean facePlayer = false;
@Property(
type = PropertyType.BOOLEAN,
description = "If Entities should be rotated sideways when carried"
)
public boolean rotateEntitiesSideways = false;
@Property( @Property(
type = PropertyType.BOOLEAN, 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)" 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)"
@ -312,7 +366,8 @@ public class CarryConfig
@Property( @Property(
type = PropertyType.STRING_ARRAY, 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" 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 = { public String[] modelOverrides = {
"minecraft:redstone_wire->(item)minecraft:redstone", "minecraft:redstone_wire->(item)minecraft:redstone",

View File

@ -1,8 +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.common.config; package tschipp.carryon.common.config;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.Identifier;
import net.minecraft.tags.TagKey; import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
@ -30,7 +50,7 @@ public class ListHandler {
private static List<TagKey<EntityType<?>>> FORBIDDEN_STACKING_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 List<TagKey<EntityType<?>>> ALLOWED_STACKING_TAGS = new ArrayList<>();
private static Set<Class<?>> PROPERTY_EXCEPTION_CLASSES = new HashSet<>(); private static Set<Property<?>> PROPERTY_EXCEPTION_CLASSES = new HashSet<>();
public static boolean isPermitted(Block block) public static boolean isPermitted(Block block)
{ {
@ -58,7 +78,7 @@ public class ListHandler {
public static boolean isPropertyException(Property<?> prop) public static boolean isPropertyException(Property<?> prop)
{ {
return PROPERTY_EXCEPTION_CLASSES.contains(prop.getValueClass()); return PROPERTY_EXCEPTION_CLASSES.contains(prop);
} }
private static boolean doCheck(Block block, Set<String> regular, List<TagKey<Block>> tags) private static boolean doCheck(Block block, Set<String> regular, List<TagKey<Block>> tags)
@ -99,8 +119,8 @@ public class ListHandler {
ALLOWED_TILES_TAGS.clear(); ALLOWED_TILES_TAGS.clear();
PROPERTY_EXCEPTION_CLASSES.clear(); PROPERTY_EXCEPTION_CLASSES.clear();
Map<ResourceLocation, TagKey<Block>> blocktags = BuiltInRegistries.BLOCK.getTagNames().collect(Collectors.toMap(t -> t.location(), t -> t)); Map<Identifier, TagKey<Block>> blocktags = BuiltInRegistries.BLOCK.listTagIds().collect(Collectors.toMap(t -> t.location(), t -> t));
Map<ResourceLocation, TagKey<EntityType<?>>> entitytags = BuiltInRegistries.ENTITY_TYPE.getTagNames().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)); List<String> forbidden = new ArrayList<>(List.of(Constants.COMMON_CONFIG.blacklist.forbiddenTiles));
forbidden.add("#carryon:block_blacklist"); forbidden.add("#carryon:block_blacklist");
@ -132,26 +152,26 @@ public class ListHandler {
continue; continue;
String name = propString.substring(0, propString.indexOf("[")); String name = propString.substring(0, propString.indexOf("["));
String props = propString.substring(propString.indexOf("[") + 1, propString.indexOf("]")); String props = propString.substring(propString.indexOf("[") + 1, propString.indexOf("]"));
Block blk = BuiltInRegistries.BLOCK.get(new ResourceLocation(name)); Block blk = BuiltInRegistries.BLOCK.get(Identifier.parse(name)).get().value();
for(String propName : props.split(",")) { for(String propName : props.split(",")) {
for (Property<?> prop : blk.defaultBlockState().getProperties()) { for (Property<?> prop : blk.defaultBlockState().getProperties()) {
if (prop.getName().equals(propName)) if (prop.getName().equals(propName))
PROPERTY_EXCEPTION_CLASSES.add(prop.getValueClass()); PROPERTY_EXCEPTION_CLASSES.add(prop);
} }
} }
} }
} }
private static <T> void addTag(String tag, Map<ResourceLocation, TagKey<T>> tagMap, List<TagKey<T>> tags) { private static <T> void addTag(String tag, Map<Identifier, TagKey<T>> tagMap, List<TagKey<T>> tags) {
String sub = tag.substring(1); String sub = tag.substring(1);
TagKey<T> t = tagMap.get(new ResourceLocation(sub)); TagKey<T> t = tagMap.get(Identifier.parse(sub));
if (t != null) if (t != null)
tags.add(t); tags.add(t);
} }
private static <T> void addWithWildcards(List<String> entries, Set<String> toAddTo, Registry<T> registry, Map<ResourceLocation, TagKey<T>> tags, List<TagKey<T>> toAddTags) { private static <T> void addWithWildcards(List<String> entries, Set<String> toAddTo, Registry<T> registry, Map<Identifier, TagKey<T>> tags, List<TagKey<T>> toAddTags) {
ResourceLocation[] keys = registry.keySet().toArray(new ResourceLocation[0]); Identifier[] keys = registry.keySet().toArray(new Identifier[0]);
for (int i = 0; i < entries.size(); i++) for (int i = 0; i < entries.size(); i++)
{ {
String curr = entries.get(i); String curr = entries.get(i);
@ -161,7 +181,7 @@ public class ListHandler {
{ {
String[] filter = curr.replace("*", ",").split(","); String[] filter = curr.replace("*", ",").split(",");
for (ResourceLocation key : keys) for (Identifier key : keys)
{ {
if (containsAll(key.toString(), filter)) if (containsAll(key.toString(), filter))

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.common.pickupcondition;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
@ -99,7 +119,7 @@ public class PickupCondition
private BlockResult parseState(String state) private BlockResult parseState(String state)
{ {
try { try {
BlockResult result = BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK.asLookup(), state, false); BlockResult result = BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK, state, false);
return result; return result;
} catch (CommandSyntaxException e) { } catch (CommandSyntaxException e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.common.pickupcondition;
import com.mojang.serialization.DataResult; import com.mojang.serialization.DataResult;

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.common.scripting;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
@ -19,12 +39,13 @@ public record CarryOnScript(
ScriptObject scriptObject, ScriptObject scriptObject,
ScriptConditions scriptConditions, ScriptConditions scriptConditions,
ScriptRender scriptRender, ScriptRender scriptRender,
ScriptEffects scriptEffects) ScriptEffects scriptEffects,
boolean overrideChecks)
{ {
public boolean isValid() public boolean isValid()
{ {
return (isBlock() ^ isEntity()) && (scriptConditions != ScriptConditions.EMPTY || scriptRender != ScriptRender.EMPTY || scriptEffects != ScriptEffects.EMPTY); return (isBlock() ^ isEntity()) && (scriptConditions != ScriptConditions.EMPTY || scriptRender != ScriptRender.EMPTY || scriptEffects != ScriptEffects.EMPTY || overrideChecks);
} }
public boolean isBlock() public boolean isBlock()
@ -43,7 +64,8 @@ public record CarryOnScript(
ScriptObject.CODEC.fieldOf("object").forGetter(CarryOnScript::scriptObject), ScriptObject.CODEC.fieldOf("object").forGetter(CarryOnScript::scriptObject),
ScriptConditions.CODEC.optionalFieldOf("conditions", ScriptConditions.EMPTY).forGetter(CarryOnScript::scriptConditions), ScriptConditions.CODEC.optionalFieldOf("conditions", ScriptConditions.EMPTY).forGetter(CarryOnScript::scriptConditions),
ScriptRender.CODEC.optionalFieldOf("render", ScriptRender.EMPTY).forGetter(CarryOnScript::scriptRender), ScriptRender.CODEC.optionalFieldOf("render", ScriptRender.EMPTY).forGetter(CarryOnScript::scriptRender),
ScriptEffects.CODEC.optionalFieldOf("effects", ScriptEffects.EMPTY).forGetter(CarryOnScript::scriptEffects) ScriptEffects.CODEC.optionalFieldOf("effects", ScriptEffects.EMPTY).forGetter(CarryOnScript::scriptEffects),
Codec.BOOL.optionalFieldOf("override_checks", false).forGetter(CarryOnScript::overrideChecks)
).apply(instance, CarryOnScript::new) ).apply(instance, CarryOnScript::new)
); );
@ -74,17 +96,15 @@ public record CarryOnScript(
public record ScriptObjectBlock( public record ScriptObjectBlock(
Optional<ResourceKey<Block>> typeNameBlock, Optional<ResourceKey<Block>> typeNameBlock,
MaterialCondition typeMaterial,
NumberBoundCondition typeHardness, NumberBoundCondition typeHardness,
NumberBoundCondition typeResistance, NumberBoundCondition typeResistance,
NBTCondition typeBlockTag NBTCondition typeBlockTag
){ ){
public static final ScriptObjectBlock EMPTY = new ScriptObjectBlock(Optional.empty(), MaterialCondition.NONE, NumberBoundCondition.NONE, NumberBoundCondition.NONE, NBTCondition.NONE); public static final ScriptObjectBlock EMPTY = new ScriptObjectBlock(Optional.empty(), NumberBoundCondition.NONE, NumberBoundCondition.NONE, NBTCondition.NONE);
public static final Codec<ScriptObjectBlock> CODEC = RecordCodecBuilder.create(instance -> public static final Codec<ScriptObjectBlock> CODEC = RecordCodecBuilder.create(instance ->
instance.group( instance.group(
ResourceKey.codec(Registries.BLOCK).optionalFieldOf("name").forGetter(ScriptObjectBlock::typeNameBlock), ResourceKey.codec(Registries.BLOCK).optionalFieldOf("name").forGetter(ScriptObjectBlock::typeNameBlock),
MaterialCondition.CODEC.optionalFieldOf("material", MaterialCondition.NONE).forGetter(ScriptObjectBlock::typeMaterial),
NumberBoundCondition.CODEC.optionalFieldOf("hardness", NumberBoundCondition.NONE).forGetter(ScriptObjectBlock::typeHardness), NumberBoundCondition.CODEC.optionalFieldOf("hardness", NumberBoundCondition.NONE).forGetter(ScriptObjectBlock::typeHardness),
NumberBoundCondition.CODEC.optionalFieldOf("resistance", NumberBoundCondition.NONE).forGetter(ScriptObjectBlock::typeResistance), NumberBoundCondition.CODEC.optionalFieldOf("resistance", NumberBoundCondition.NONE).forGetter(ScriptObjectBlock::typeResistance),
NBTCondition.CODEC.optionalFieldOf("nbt", NBTCondition.NONE).forGetter(ScriptObjectBlock::typeBlockTag) NBTCondition.CODEC.optionalFieldOf("nbt", NBTCondition.NONE).forGetter(ScriptObjectBlock::typeBlockTag)

View File

@ -1,23 +1,44 @@
/*
* 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; package tschipp.carryon.common.scripting;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import net.minecraft.advancements.Advancement; import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.advancements.AdvancementHolder;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.NbtUtils;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.Identifier;
import net.minecraft.server.ServerAdvancementManager; import net.minecraft.server.ServerAdvancementManager;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.Objective; import net.minecraft.world.scores.Objective;
import net.minecraft.world.scores.Score;
import net.minecraft.world.scores.Scoreboard; import net.minecraft.world.scores.Scoreboard;
import tschipp.carryon.platform.Services; import tschipp.carryon.platform.Services;
import java.util.*; import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
public final class Matchables public final class Matchables
{ {
@ -97,91 +118,6 @@ public final class Matchables
} }
} }
public record MaterialCondition(String material) implements Matchable<Material>
{
public static final Codec<MaterialCondition> CODEC = Codec.STRING.xmap(MaterialCondition::new, MaterialCondition::material);
public static final MaterialCondition NONE = new MaterialCondition("");
@Override
public boolean matches(Material material)
{
if (this.material == null || this.material.isEmpty())
return true;
switch (this.material) {
case "air":
return material == Material.AIR;
case "anvil":
return material == Material.HEAVY_METAL;
case "barrier":
return material == Material.BARRIER;
case "cactus":
return material == Material.CACTUS;
case "cake":
return material == Material.CAKE;
case "carpet":
return material == Material.CLOTH_DECORATION;
case "clay":
return material == Material.CLAY;
case "cloth":
return material == Material.WOOL;
case "dragon_egg":
return material == Material.EGG;
case "fire":
return material == Material.FIRE;
case "glass":
return material == Material.GLASS;
case "gourd":
return material == Material.VEGETABLE;
case "grass":
return material == Material.GRASS;
case "ground":
return material == Material.GRASS;
case "ice":
return material == Material.ICE;
case "iron":
return material == Material.METAL;
case "lava":
return material == Material.LAVA;
case "leaves":
return material == Material.LEAVES;
case "packed_ice":
return material == Material.ICE_SOLID;
case "piston":
return material == Material.PISTON;
case "plants":
return material == Material.PLANT;
case "portal":
return material == Material.PORTAL;
case "redstone_light":
return material == Material.BUILDABLE_GLASS;
case "rock":
return material == Material.STONE;
case "sand":
return material == Material.SAND;
case "snow":
return material == Material.TOP_SNOW;
case "sponge":
return material == Material.SPONGE;
case "structure_void":
return material == Material.STRUCTURAL_AIR;
case "tnt":
return material == Material.EXPLOSIVE;
case "vine":
return material == Material.PLANT;
case "water":
return material == Material.WATER;
case "web":
return material == Material.WEB;
case "wood":
return material == Material.WOOD;
default:
return false;
}
}
}
public record AdvancementCondition(String advancement) implements Matchable<ServerPlayer> public record AdvancementCondition(String advancement) implements Matchable<ServerPlayer>
{ {
public static final Codec<AdvancementCondition> CODEC = Codec.STRING.xmap(AdvancementCondition::new, AdvancementCondition::advancement); public static final Codec<AdvancementCondition> CODEC = Codec.STRING.xmap(AdvancementCondition::new, AdvancementCondition::advancement);
@ -191,8 +127,8 @@ public final class Matchables
@Override @Override
public boolean matches(ServerPlayer player) public boolean matches(ServerPlayer player)
{ {
ServerAdvancementManager manager = player.server.getAdvancements(); ServerAdvancementManager manager = player.level().getServer().getAdvancements();
Advancement adv = manager.getAdvancement(new ResourceLocation(advancement.isEmpty() ? "" : advancement)); AdvancementHolder adv = manager.get(Identifier.parse(advancement.isEmpty() ? "" : advancement));
boolean achievement = adv == null ? true : player.getAdvancements().getOrStartProgress(adv).isDone(); boolean achievement = adv == null ? true : player.getAdvancements().getOrStartProgress(adv).isDone();
return achievement; return achievement;
@ -231,7 +167,7 @@ public final class Matchables
if (cond == null || cond.isEmpty()) if (cond == null || cond.isEmpty())
return true; return true;
Scoreboard score = player.getScoreboard(); Scoreboard score = player.level().getScoreboard();
String numb; String numb;
String scorename; String scorename;
int iE = cond.indexOf("="); int iE = cond.indexOf("=");
@ -246,19 +182,10 @@ public final class Matchables
numb = cond.substring(iL); numb = cond.substring(iL);
scorename = cond.replace(numb, ""); scorename = cond.replace(numb, "");
Map<Objective, Score> o = score.getPlayerScores(player.getGameProfile().getName()); Object2IntMap<Objective> scores = score.listPlayerScores(player);
if (o != null) int scoreVal = scores.getInt(score.getObjective(scorename));
{
Score sc = o.get(score.getObjective(scorename));
if (sc != null)
{
int points = sc.getScore();
return new NumberBoundCondition(numb).matches(points); return new NumberBoundCondition(numb).matches(scoreVal);
}
}
return false;
} }
} }
@ -336,7 +263,7 @@ public final class Matchables
for (MobEffectInstance effect : fx) for (MobEffectInstance effect : fx)
{ {
int amp = effect.getAmplifier(); int amp = effect.getAmplifier();
String name = BuiltInRegistries.MOB_EFFECT.getKey(effect.getEffect()).toString(); String name = effect.getEffect().getRegisteredName();
if (names.contains(name)) if (names.contains(name))
{ {

View File

@ -1,14 +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.common.scripting; package tschipp.carryon.common.scripting;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Material; import net.minecraft.world.level.storage.TagValueOutput;
import tschipp.carryon.Constants; import tschipp.carryon.Constants;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectBlock; import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectBlock;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectEntity; import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectEntity;
@ -28,13 +49,12 @@ public class ScriptManager
return Optional.empty(); return Optional.empty();
Block block = state.getBlock(); Block block = state.getBlock();
Material material = state.getMaterial();
float hardness = state.getDestroySpeed(level, pos); float hardness = state.getDestroySpeed(level, pos);
float resistance = block.getExplosionResistance(); float resistance = block.getExplosionResistance();
for (CarryOnScript script : SCRIPTS) for (CarryOnScript script : SCRIPTS)
{ {
if (script.isBlock() && matchesAll(script, block, material, hardness, resistance, tag)) if (script.isBlock() && matchesAll(script, block, hardness, resistance, tag))
return Optional.of(script); return Optional.of(script);
} }
@ -49,8 +69,9 @@ public class ScriptManager
float height = entity.getBbHeight(); float height = entity.getBbHeight();
float width = entity.getBbWidth(); float width = entity.getBbWidth();
float health = entity instanceof LivingEntity ? ((LivingEntity) entity).getHealth() : 0.0f; float health = entity instanceof LivingEntity ? ((LivingEntity) entity).getHealth() : 0.0f;
CompoundTag tag = new CompoundTag(); TagValueOutput output = TagValueOutput.createWithContext(new ProblemReporter.ScopedCollector(Constants.LOG), entity.registryAccess());
entity.save(tag); entity.save(output);
CompoundTag tag = output.buildResult();
for (CarryOnScript script : SCRIPTS) for (CarryOnScript script : SCRIPTS)
{ {
@ -76,18 +97,17 @@ public class ScriptManager
return matchname && matchheight && matchwidth && matchhealth && matchnbt; return matchname && matchheight && matchwidth && matchhealth && matchnbt;
} }
private static boolean matchesAll(CarryOnScript script, Block block, Material material, float hardness, float resistance, CompoundTag nbt) private static boolean matchesAll(CarryOnScript script, Block block, float hardness, float resistance, CompoundTag nbt)
{ {
ScriptObjectBlock scBlock = script.scriptObject().block(); ScriptObjectBlock scBlock = script.scriptObject().block();
boolean matchblock = true; boolean matchblock = true;
if(scBlock.typeNameBlock().isPresent()) if(scBlock.typeNameBlock().isPresent())
matchblock = block == BuiltInRegistries.BLOCK.get(scBlock.typeNameBlock().get()); matchblock = block == BuiltInRegistries.BLOCK.get(scBlock.typeNameBlock().get()).get().value();
boolean matchnbt = scBlock.typeBlockTag().matches(nbt); boolean matchnbt = scBlock.typeBlockTag().matches(nbt);
boolean matchmaterial = scBlock.typeMaterial().matches(material);
boolean matchhardness = scBlock.typeHardness().matches(hardness); boolean matchhardness = scBlock.typeHardness().matches(hardness);
boolean matchresistance = scBlock.typeResistance().matches(resistance); boolean matchresistance = scBlock.typeResistance().matches(resistance);
return matchnbt && matchblock && matchmaterial && matchhardness && matchresistance; return matchnbt && matchblock && matchhardness && matchresistance;
} }
} }

View File

@ -1,67 +1,69 @@
/*
* 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; package tschipp.carryon.common.scripting;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult; import com.mojang.serialization.DataResult;
import com.mojang.serialization.JsonOps;
import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.FileToIdConverter;
import net.minecraft.resources.Identifier;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener; import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.util.profiling.ProfilerFiller;
import org.jetbrains.annotations.NotNull;
import tschipp.carryon.Constants; import tschipp.carryon.Constants;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.networking.clientbound.ClientboundSyncScriptsPacket; import tschipp.carryon.networking.clientbound.ClientboundSyncScriptsPacket;
import tschipp.carryon.platform.Services; import tschipp.carryon.platform.Services;
import java.util.Collections;
import java.util.Map; import java.util.Map;
public class ScriptReloadListener extends SimpleJsonResourceReloadListener public class ScriptReloadListener extends SimpleJsonResourceReloadListener<CarryOnScript>
{ {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
public ScriptReloadListener() public ScriptReloadListener()
{ {
super(GSON, "carryon/scripts"); super(CarryOnScript.CODEC, FileToIdConverter.json("carryon/scripts"));
} }
@Override @Override
protected void apply(Map<ResourceLocation, JsonElement> objects, ResourceManager manager, ProfilerFiller profiler) protected void apply(Map<Identifier, CarryOnScript> scripts, @NotNull ResourceManager resourceManager, @NotNull ProfilerFiller profilerFiller)
{ {
ScriptManager.SCRIPTS.clear(); ScriptManager.SCRIPTS.clear();
try { scripts.forEach((path, script) -> {
objects.forEach((path, jsonElem) -> { if (script.isValid())
DataResult<CarryOnScript> res = CarryOnScript.CODEC.parse(JsonOps.INSTANCE, jsonElem); ScriptManager.SCRIPTS.add(script);
if(res.result().isPresent()) });
{
CarryOnScript script = res.result().get();
if (script.isValid())
ScriptManager.SCRIPTS.add(script);
}
else
Constants.LOG.warn("Error while parsing script: " + res.error().get().message());
});
}
catch (Exception e)
{
e.printStackTrace();
}
Collections.sort(ScriptManager.SCRIPTS, (s1, s2) -> Long.compare(s2.priority(), s1.priority())); ScriptManager.SCRIPTS.sort((s1, s2) -> Long.compare(s2.priority(), s1.priority()));
} }
public static void syncScriptsWithClient(ServerPlayer player) public static void syncScriptsWithClient(ServerPlayer player)
{ {
if (player != null) if (player != null)
{ {
DataResult<Tag> result = Codec.list(CarryOnScript.CODEC).encodeStart(NbtOps.INSTANCE, ScriptManager.SCRIPTS); DataResult<Tag> result = Codec.list(CarryOnScript.CODEC).encodeStart(NbtOps.INSTANCE, ScriptManager.SCRIPTS);
Tag tag = result.getOrThrow(false, s -> {throw new RuntimeException("Error while synching Carry On Scripts: " + s);}); 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); 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

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.config;
@ -9,7 +29,8 @@ public record AnnotationData(
PropertyType type, PropertyType type,
String description, String description,
int min, int max, int min, int max,
double minD, double maxD double minD, double maxD,
String validationRegex
) { ) {
public static AnnotationData getData(Field field) { public static AnnotationData getData(Field field) {
@ -18,7 +39,8 @@ public record AnnotationData(
annotation.type(), annotation.type(),
annotation.description(), annotation.description(),
annotation.min(), annotation.max(), annotation.min(), annotation.max(),
annotation.minD(), annotation.maxD() annotation.minD(), annotation.maxD(),
annotation.validationRegex()
); );
} }
} }

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.config;
import java.util.ArrayList; import java.util.ArrayList;
@ -12,9 +32,12 @@ public class BuiltCategory {
public final String categoryDesc; public final String categoryDesc;
public final String category; public final String category;
public BuiltCategory(String categoryDesc, String category) { public final String translation;
public BuiltCategory(String categoryDesc, String category, String translation) {
this.categoryDesc = categoryDesc; this.categoryDesc = categoryDesc;
this.category = category; this.category = category;
this.translation = translation;
} }
public Optional<PropertyData> getProperty(String id) { public Optional<PropertyData> getProperty(String id) {

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.config;
public class BuiltConfig extends BuiltCategory { public class BuiltConfig extends BuiltCategory {
@ -5,7 +25,7 @@ public class BuiltConfig extends BuiltCategory {
public final String fileName; public final String fileName;
public BuiltConfig(String fileName) { public BuiltConfig(String fileName) {
super(null, fileName); super(null, fileName, "key.carry.category");
this.fileName = fileName; this.fileName = fileName;
} }
} }

View File

@ -1,7 +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.config; package tschipp.carryon.config;
//Many Thanks to ThatGravyBoat for this template! //Many Thanks to ThatGravyBoat for this template!
import net.minecraft.core.HolderLookup;
import tschipp.carryon.client.modeloverride.ModelOverrideHandler; import tschipp.carryon.client.modeloverride.ModelOverrideHandler;
import tschipp.carryon.common.config.ListHandler; import tschipp.carryon.common.config.ListHandler;
import tschipp.carryon.common.pickupcondition.PickupConditionHandler; import tschipp.carryon.common.pickupcondition.PickupConditionHandler;
@ -33,10 +54,10 @@ public class ConfigLoader {
Services.PLATFORM.registerConfig(config); Services.PLATFORM.registerConfig(config);
} }
public static void onConfigLoaded() { public static void onConfigLoaded(HolderLookup.Provider provider) {
ListHandler.initConfigLists(); ListHandler.initConfigLists();
PickupConditionHandler.initPickupConditions(); PickupConditionHandler.initPickupConditions();
ModelOverrideHandler.initModelOverrides(); ModelOverrideHandler.initModelOverrides(provider);
} }
public static BuiltCategory buildCategory(String categoryDesc, Object object) throws IllegalAccessException { public static BuiltCategory buildCategory(String categoryDesc, Object object) throws IllegalAccessException {
@ -45,7 +66,7 @@ public class ConfigLoader {
if (configClass.isAnnotationPresent(Config.class)) { if (configClass.isAnnotationPresent(Config.class)) {
category = new BuiltConfig(configClass.getAnnotation(Config.class).value()); category = new BuiltConfig(configClass.getAnnotation(Config.class).value());
} else if (configClass.isAnnotationPresent(Category.class)) { } else if (configClass.isAnnotationPresent(Category.class)) {
category = new BuiltCategory(categoryDesc, configClass.getAnnotation(Category.class).value()); category = new BuiltCategory(categoryDesc, configClass.getAnnotation(Category.class).value(), configClass.getAnnotation(Category.class).translation());
} else { } else {
throw new IllegalStateException("Config does not contain any @Config annotation or @Category"); throw new IllegalStateException("Config does not contain any @Config annotation or @Category");
} }
@ -56,7 +77,7 @@ public class ConfigLoader {
if (type.equals(PropertyType.CATEGORY)) { if (type.equals(PropertyType.CATEGORY)) {
category.categories.add(buildCategory(field.getAnnotation(Property.class).description(), field.get(object))); category.categories.add(buildCategory(field.getAnnotation(Property.class).description(), field.get(object)));
} else { } else {
category.properties.add(new PropertyData(object, field, AnnotationData.getData(field))); category.properties.add(new PropertyData(object, field, AnnotationData.getData(field), field.get(object)));
} }
} }
} }

View File

@ -1,15 +1,69 @@
/*
* 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; package tschipp.carryon.config;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.function.Consumer;
public record PropertyData(Object fieldClass, Field field, AnnotationData data) { 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() { public String getId() {
return field().getName(); return field.getName();
} }
public boolean getBoolean() throws IllegalAccessException { public boolean getBoolean() throws IllegalAccessException {
return field().getBoolean(fieldClass()); return field.getBoolean(fieldClass);
} }
public void setBoolean(boolean _boolean) { public void setBoolean(boolean _boolean) {
@ -20,8 +74,12 @@ public record PropertyData(Object fieldClass, Field field, AnnotationData data)
} }
} }
public boolean getDefaultBoolean() {
return (boolean)defaultValue;
}
public int getInt() throws IllegalAccessException { public int getInt() throws IllegalAccessException {
return field().getInt(fieldClass()); return field.getInt(fieldClass);
} }
public void setInt(int _int) { public void setInt(int _int) {
@ -32,8 +90,12 @@ public record PropertyData(Object fieldClass, Field field, AnnotationData data)
} }
} }
public int getDefaultInt() {
return (int)defaultValue;
}
public double getDouble() throws IllegalAccessException { public double getDouble() throws IllegalAccessException {
return field().getDouble(fieldClass()); return field.getDouble(fieldClass);
} }
public void setDouble(double _double) { public void setDouble(double _double) {
@ -44,8 +106,12 @@ public record PropertyData(Object fieldClass, Field field, AnnotationData data)
} }
} }
public double getDefaultDouble() {
return (double)defaultValue;
}
public String[] getStringArray() throws IllegalAccessException { public String[] getStringArray() throws IllegalAccessException {
return (String[])field().get(fieldClass()); return (String[])field.get(fieldClass);
} }
public void setStringArray(String[] arr) public void setStringArray(String[] arr)
@ -56,4 +122,8 @@ public record PropertyData(Object fieldClass, Field field, AnnotationData data)
//Ignore //Ignore
} }
} }
public String[] getDefaultStringArray() {
return (String[])defaultValue;
}
} }

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.config;
public enum PropertyType { public enum PropertyType {

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.config.annotations;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
@ -9,4 +29,5 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Category { public @interface Category {
String value(); String value();
String translation() default "";
} }

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.config.annotations;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.config.annotations;
import tschipp.carryon.config.PropertyType; import tschipp.carryon.config.PropertyType;
@ -12,7 +32,6 @@ import java.lang.annotation.Target;
public @interface Property { public @interface Property {
PropertyType type(); PropertyType type();
String description(); String description();
@ -21,4 +40,6 @@ public @interface Property {
double minD() default Double.MIN_VALUE; double minD() default Double.MIN_VALUE;
double maxD() default Double.MAX_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

@ -1,5 +1,26 @@
/*
* 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; package tschipp.carryon.mixin;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
@ -27,6 +48,13 @@ public abstract class EntityMixin
@Shadow @Shadow
public boolean hasPassenger(Entity pEntity) {throw new IllegalStateException("EntityMixin application failed");} 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); @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) @Inject(method = "positionRider(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/entity/Entity$MoveFunction;)V", at = @At("HEAD"), cancellable = true)
@ -65,7 +93,7 @@ public abstract class EntityMixin
@Inject(method = "onPassengerTurned(Lnet/minecraft/world/entity/Entity;)V", at = @At("HEAD")) @Inject(method = "onPassengerTurned(Lnet/minecraft/world/entity/Entity;)V", at = @At("HEAD"))
private void onPassengerTurned(Entity toUpdate, CallbackInfo ci) private void onPassengerTurned(Entity toUpdate, CallbackInfo ci)
{ {
if((Object)this instanceof Player thisPlayer && toUpdate instanceof Player otherPlayer) if((Object)this instanceof Player thisPlayer && toUpdate instanceof Player)
{ {
CarryOnData carry = CarryOnDataManager.getCarryData(thisPlayer); CarryOnData carry = CarryOnDataManager.getCarryData(thisPlayer);
if(carry.isCarrying(CarryType.PLAYER)) { if(carry.isCarrying(CarryType.PLAYER)) {

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

@ -1,9 +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.mixin; package tschipp.carryon.mixin;
import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.geom.ModelPart; import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.client.renderer.entity.state.HumanoidRenderState;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@ -12,9 +31,8 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import tschipp.carryon.Constants; import tschipp.carryon.Constants;
import tschipp.carryon.client.render.CarryRenderHelper; import tschipp.carryon.client.render.ICarryOnRenderState;
import tschipp.carryon.common.carry.CarryOnData; import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.common.scripting.CarryOnScript.ScriptRender; import tschipp.carryon.common.scripting.CarryOnScript.ScriptRender;
@Mixin(HumanoidModel.class) @Mixin(HumanoidModel.class)
@ -26,20 +44,20 @@ public class HumanoidModelMixin {
@Shadow @Shadow
public ModelPart leftArm; public ModelPart leftArm;
@Inject(at = @At("RETURN"), method = "setupAnim(Lnet/minecraft/world/entity/LivingEntity;FFFFF)V") @Inject(at = @At("RETURN"), method = "setupAnim(Lnet/minecraft/client/renderer/entity/state/HumanoidRenderState;)V")
private void onSetupAnimations(LivingEntity living, float f1, float f2, float f3, float f4, float f5, CallbackInfo ci) private void onSetupAnimations(HumanoidRenderState state, CallbackInfo ci)
{ {
if(living instanceof Player player && Constants.CLIENT_CONFIG.renderArms) if(state instanceof ICarryOnRenderState carryOnRenderState && Constants.CLIENT_CONFIG.renderArms)
{ {
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = carryOnRenderState.getCarryOnData();
if(carry.isCarrying() && !player.isVisuallySwimming() && !player.isFallFlying()) if(carry != null && carry.isCarrying() && !state.isVisuallySwimming && !state.isFallFlying)
{ {
boolean sneaking = !player.getAbilities().flying && player.isShiftKeyDown() || player.isCrouching(); boolean sneaking = state.isCrouching;
float x = 1.0f + (sneaking ? 0.2f : 0.0f) + (carry.isCarrying(CarryOnData.CarryType.BLOCK) ? 0.0f : 0.3f); float x = 1.0f + (sneaking ? 0.2f : 0.0f) + (carry.isCarrying(CarryOnData.CarryType.BLOCK) ? 0.0f : 0.3f);
float z = 0.05f; float z = 0.05f;
float width = CarryRenderHelper.getRenderWidth(player); float width = carryOnRenderState.getRenderWidth();
float offset = Math.min((width - 1) / 1.5f, 0.2f); float offset = Math.min((width - 1) / 1.5f, 0.2f);
if(carry.getActiveScript().isPresent()) if(carry.getActiveScript().isPresent())

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.mixin;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
@ -9,15 +29,17 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; 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.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager; import tschipp.carryon.common.carry.CarryOnDataManager;
@Mixin(Inventory.class) @Mixin(Inventory.class)
public class InventoryMixin public class InventoryMixin
{ {
@Unique
private static final ItemStack DUMMY_STACK = new ItemStack(Blocks.COBBLESTONE, 1); private static final ItemStack DUMMY_STACK = new ItemStack(Blocks.COBBLESTONE, 1);
@Shadow @Shadow
@ -40,7 +62,7 @@ public class InventoryMixin
return original.call(instance, slot); return original.call(instance, slot);
} }
@Inject(method = "setPickedItem(Lnet/minecraft/world/item/ItemStack;)V", at = @At("HEAD"), cancellable = true) @Inject(method = "addAndPickItem(Lnet/minecraft/world/item/ItemStack;)V", at = @At("HEAD"), cancellable = true)
private void onPickBlock(CallbackInfo info) private void onPickBlock(CallbackInfo info)
{ {
if(CarryOnDataManager.getCarryData(player).isCarrying()) if(CarryOnDataManager.getCarryData(player).isCarrying())
@ -54,10 +76,11 @@ public class InventoryMixin
info.cancel(); info.cancel();
} }
@Inject(method = "swapPaint(D)V", at = @At("HEAD"), cancellable = true) @Inject(method = "setSelectedSlot(I)V", at = @At("HEAD"), cancellable = true)
private void onSwapPaint(double direction, CallbackInfo info) private void onSwapPaint(int slot, CallbackInfo info)
{ {
if(CarryOnDataManager.getCarryData(player).isCarrying()) CarryOnData data = CarryOnDataManager.getCarryData(player);
if(data.isCarrying() && data.getSelected() != slot)
info.cancel(); info.cancel();
} }
} }

View File

@ -1,19 +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; package tschipp.carryon.mixin;
import com.llamalad7.mixinextras.injector.WrapWithCondition; import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import tschipp.carryon.common.carry.CarryOnDataManager; import tschipp.carryon.common.carry.CarryOnDataManager;
@Mixin(Minecraft.class) @Mixin(Minecraft.class)
public class MinecraftMixin public class MinecraftMixin {
{
@WrapWithCondition(method = "handleKeybinds()V", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/player/Inventory;selected:I", ordinal = 0, opcode = 181)) //Opcode for PUTFIELD @WrapWithCondition(
private boolean allowSlotSelection(Inventory inv,int slot) method = "handleKeybinds()V",
{ at = @At(
return !CarryOnDataManager.getCarryData(inv.player).isCarrying(); 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

@ -1,44 +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; package tschipp.carryon.mixin;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.storage.ValueInput;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import tschipp.carryon.common.carry.CarryOnData; import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnData.CarryType;
import tschipp.carryon.common.carry.CarryOnDataManager; import tschipp.carryon.common.carry.CarryOnDataManager;
import java.util.Optional;
@Mixin(Player.class) @Mixin(Player.class)
public abstract class PlayerMixin extends LivingEntity { public abstract class PlayerMixin extends LivingEntity {
private PlayerMixin(EntityType<? extends LivingEntity> type, Level level) { private PlayerMixin(EntityType<? extends LivingEntity> type, Level level) {
super(type, level); super(type, level);
} }
@Inject(method = "defineSynchedData()V", at = @At("RETURN")) //We leave this in here to ensure cross-compatibility if world are upgraded from <1.21.8. Should be removed in the future.
private void onDefineSynchedData(CallbackInfo info) { @Inject(method = "readAdditionalSaveData(Lnet/minecraft/world/level/storage/ValueInput;)V", at = @At("RETURN"))
this.entityData.define(CarryOnDataManager.CARRY_DATA_KEY, new CompoundTag()); private void onReadAdditionalSaveData(ValueInput input, CallbackInfo ci)
{
Optional<CarryOnData> res = input.read("CarryOnData", CarryOnData.CODEC);
res.ifPresent(data -> CarryOnDataManager.setCarryData((Player)((Object)this), data));
} }
@Inject(method = "addAdditionalSaveData(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("RETURN"))
private void onAddAdditionalSaveData(CompoundTag tag, CallbackInfo info)
{
CarryOnData carry = CarryOnDataManager.getCarryData((Player)(Object)this);
tag.put("CarryOnData", carry.getNbt());
}
@Inject(method = "readAdditionalSaveData(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("RETURN")) @Override
private void onReadAdditionalSaveData(CompoundTag tag, CallbackInfo info) public void stopRiding() {
{ Entity entity = this.getVehicle();
if (tag.contains("CarryOnData")) { if (entity instanceof Player && entity.getPassengers().size() < 2){
CarryOnData data = new CarryOnData(tag.getCompound("CarryOnData")); CarryOnData carry = CarryOnDataManager.getCarryData((Player) entity);
CarryOnDataManager.setCarryData((Player) (Object) this, data); 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

@ -1,11 +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; package tschipp.carryon.networking;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
public abstract class PacketBase public interface PacketBase extends CustomPacketPayload {
{
public abstract void toBytes(FriendlyByteBuf buf);
public abstract void handle(Player player); 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

@ -1,42 +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; package tschipp.carryon.networking.clientbound;
import net.minecraft.network.FriendlyByteBuf; 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.Entity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import tschipp.carryon.Constants;
import tschipp.carryon.networking.PacketBase; import tschipp.carryon.networking.PacketBase;
public class ClientboundStartRidingPacket extends PacketBase public record ClientboundStartRidingPacket(int iden, boolean ride) implements PacketBase
{ {
int entityId; public static final StreamCodec<RegistryFriendlyByteBuf, ClientboundStartRidingPacket> CODEC = StreamCodec.composite(
boolean ride; ByteBufCodecs.INT, ClientboundStartRidingPacket::iden,
ByteBufCodecs.BOOL, ClientboundStartRidingPacket::ride,
ClientboundStartRidingPacket::new
);
public ClientboundStartRidingPacket(FriendlyByteBuf buf) public static final CustomPacketPayload.Type<ClientboundStartRidingPacket> TYPE = new Type<>(Constants.PACKET_ID_START_RIDING);
{
this.entityId = buf.readInt();
this.ride = buf.readBoolean();
}
public ClientboundStartRidingPacket(int id, boolean ride)
{
this.entityId = id;
this.ride = ride;
}
@Override
public void toBytes(FriendlyByteBuf buf)
{
buf.writeInt(entityId);
buf.writeBoolean(ride);
}
@Override @Override
public void handle(Player player) public void handle(Player player)
{ {
Entity otherPlayer = player.level.getEntity(this.entityId); Entity otherPlayer = player.level().getEntity(this.iden);
if(otherPlayer != null) if(otherPlayer != null)
if(ride) if(ride)
otherPlayer.startRiding(player); otherPlayer.startRiding(player);
else else
otherPlayer.stopRiding(); otherPlayer.stopRiding();
} }
@Override
public Type<ClientboundStartRidingPacket> type() {
return TYPE;
}
} }

View File

@ -1,46 +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; package tschipp.carryon.networking.clientbound;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult; import com.mojang.serialization.DataResult;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf; 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 net.minecraft.world.entity.player.Player;
import tschipp.carryon.Constants;
import tschipp.carryon.common.scripting.CarryOnScript; import tschipp.carryon.common.scripting.CarryOnScript;
import tschipp.carryon.common.scripting.ScriptManager; import tschipp.carryon.common.scripting.ScriptManager;
import tschipp.carryon.networking.PacketBase; import tschipp.carryon.networking.PacketBase;
import java.util.List; import java.util.List;
public class ClientboundSyncScriptsPacket extends PacketBase public record ClientboundSyncScriptsPacket(Tag serialized) implements PacketBase
{ {
private Tag serialized; public static final StreamCodec<RegistryFriendlyByteBuf, ClientboundSyncScriptsPacket> CODEC = StreamCodec.composite(
ByteBufCodecs.TAG, ClientboundSyncScriptsPacket::serialized,
ClientboundSyncScriptsPacket::new
);
public ClientboundSyncScriptsPacket(FriendlyByteBuf buf) public static final CustomPacketPayload.Type<ClientboundSyncScriptsPacket> TYPE = new Type<>(Constants.PACKET_ID_SYNC_SCRIPTS);
{
this.serialized = buf.readNbt().get("data");
}
public ClientboundSyncScriptsPacket(Tag serialized)
{
this.serialized = serialized;
}
@Override
public void toBytes(FriendlyByteBuf buf)
{
CompoundTag tag = new CompoundTag();
tag.put("data", serialized);
buf.writeNbt(tag);
}
@Override @Override
public void handle(Player player) public void handle(Player player)
{ {
DataResult<List<CarryOnScript>> res = Codec.list(CarryOnScript.CODEC).parse(NbtOps.INSTANCE, serialized); DataResult<List<CarryOnScript>> res = Codec.list(CarryOnScript.CODEC).parse(NbtOps.INSTANCE, serialized);
List<CarryOnScript> scripts = res.getOrThrow(false, (s) -> {throw new RuntimeException("Failed deserializing carry on scripts on the client: " + s);}); List<CarryOnScript> scripts = res.getOrThrow((s) -> {throw new RuntimeException("Failed deserializing carry on scripts on the client: " + s);});
ScriptManager.SCRIPTS.clear(); ScriptManager.SCRIPTS.clear();
ScriptManager.SCRIPTS.addAll(scripts); ScriptManager.SCRIPTS.addAll(scripts);
} }
@Override
public Type<ClientboundSyncScriptsPacket> type() {
return TYPE;
}
} }

View File

@ -1,31 +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.networking.serverbound; package tschipp.carryon.networking.serverbound;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer; 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 net.minecraft.world.entity.player.Player;
import tschipp.carryon.Constants;
import tschipp.carryon.common.carry.CarryOnData; import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.common.carry.CarryOnDataManager; import tschipp.carryon.common.carry.CarryOnDataManager;
import tschipp.carryon.networking.PacketBase; import tschipp.carryon.networking.PacketBase;
public class ServerboundCarryKeyPressedPacket extends PacketBase public record ServerboundCarryKeyPressedPacket(boolean pressed) implements PacketBase
{ {
boolean pressed; public static final StreamCodec<RegistryFriendlyByteBuf, ServerboundCarryKeyPressedPacket> CODEC = StreamCodec.composite(
ByteBufCodecs.BOOL, ServerboundCarryKeyPressedPacket::pressed,
ServerboundCarryKeyPressedPacket::new
);
public ServerboundCarryKeyPressedPacket(FriendlyByteBuf buf) public static final CustomPacketPayload.Type<ServerboundCarryKeyPressedPacket> TYPE = new Type<>(Constants.PACKET_ID_KEY_PRESSED);
{
this.pressed = buf.readBoolean();
}
public ServerboundCarryKeyPressedPacket(boolean pressed)
{
this.pressed = pressed;
}
@Override
public void toBytes(FriendlyByteBuf buf)
{
buf.writeBoolean(pressed);
}
@Override @Override
public void handle(Player player) public void handle(Player player)
@ -34,4 +46,9 @@ public class ServerboundCarryKeyPressedPacket extends PacketBase
carry.setKeyPressed(this.pressed); carry.setKeyPressed(this.pressed);
CarryOnDataManager.setCarryData(player, carry); CarryOnDataManager.setCarryData(player, carry);
} }
@Override
public Type<ServerboundCarryKeyPressedPacket> type() {
return TYPE;
}
} }

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.platform;
import tschipp.carryon.Constants; import tschipp.carryon.Constants;

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.platform.services;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;

View File

@ -1,14 +1,37 @@
/*
* 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; package tschipp.carryon.platform.services;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation; 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.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.config.BuiltConfig; import tschipp.carryon.config.BuiltConfig;
import tschipp.carryon.networking.PacketBase; import tschipp.carryon.networking.PacketBase;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Function;
public interface IPlatformHelper { public interface IPlatformHelper {
@ -36,12 +59,21 @@ public interface IPlatformHelper {
void registerConfig(BuiltConfig cfg); void registerConfig(BuiltConfig cfg);
<T extends PacketBase> void registerServerboundPacket(ResourceLocation id, int numericalId, Class<T> clazz, BiConsumer<T, FriendlyByteBuf> writer, Function<FriendlyByteBuf, T> reader, BiConsumer<T, Player> handler); <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> void registerClientboundPacket(ResourceLocation id, int numericalId, Class<T> clazz, BiConsumer<T, FriendlyByteBuf> writer, Function<FriendlyByteBuf, T> reader, BiConsumer<T, Player> handler); <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(ResourceLocation id, PacketBase packet); void sendPacketToServer(Identifier id, PacketBase packet);
void sendPacketToPlayer(ResourceLocation id, PacketBase packet, ServerPlayer player); 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

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.utils;
public class StringHelper public class StringHelper

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

@ -12,5 +12,5 @@
"carryon.category.custompickupconditions.custompickupconditionsentities": "suoᴉʇᴉpuoƆ dnʞɔᴉԀ ʎʇᴉʇuƎ ɯoʇsnƆ", "carryon.category.custompickupconditions.custompickupconditionsentities": "suoᴉʇᴉpuoƆ dnʞɔᴉԀ ʎʇᴉʇuƎ ɯoʇsnƆ",
"key.carry.desc": "ʎɹɹɐƆ", "key.carry.desc": "ʎɹɹɐƆ",
"key.carry.category": "uO ʎɹɹɐƆ" "key.category.carryon.key.carry.category": "uO ʎɹɹɐƆ"
} }

View File

@ -12,5 +12,5 @@
"carryon.category.custompickupconditions.custompickupconditionsentities": "Custom Entity Pickup Conditions", "carryon.category.custompickupconditions.custompickupconditionsentities": "Custom Entity Pickup Conditions",
"key.carry.desc": "Carry", "key.carry.desc": "Carry",
"key.carry.category": "Carry On" "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

@ -12,5 +12,5 @@
"carryon.category.custompickupconditions.custompickupconditionsentities": "Customizar condiciones para recoger entidades", "carryon.category.custompickupconditions.custompickupconditionsentities": "Customizar condiciones para recoger entidades",
"key.carry.desc": "Agarrar", "key.carry.desc": "Agarrar",
"key.carry.category": "Carry On" "key.category.carryon.key.carry.category": "Carry On"
} }

View File

@ -12,5 +12,5 @@
"carryon.category.custompickupconditions.custompickupconditionsentities": "Conditions de ramassage d'entités personalisés", "carryon.category.custompickupconditions.custompickupconditionsentities": "Conditions de ramassage d'entités personalisés",
"key.carry.desc": "Saisir", "key.carry.desc": "Saisir",
"key.carry.category": "Carry On" "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

@ -12,5 +12,5 @@
"carryon.category.custompickupconditions.custompickupconditionsentities": "Condizioni di prelievo entità personalizzate", "carryon.category.custompickupconditions.custompickupconditionsentities": "Condizioni di prelievo entità personalizzate",
"key.carry.desc": "Afferra", "key.carry.desc": "Afferra",
"key.carry.category": "Carry On Mod" "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

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

View File

@ -12,5 +12,5 @@
"carryon.category.custompickupconditions.custompickupconditionsentities": "Пользовательские условия поднятия сущности", "carryon.category.custompickupconditions.custompickupconditionsentities": "Пользовательские условия поднятия сущности",
"key.carry.desc": "Поднять", "key.carry.desc": "Поднять",
"key.carry.category": "Carry On" "key.category.carryon.key.carry.category": "Carry On"
} }

View File

@ -2,7 +2,7 @@
"__comment__": "Translated by @alpeerkaraca", "__comment__": "Translated by @alpeerkaraca",
"carryon.category.settings": "Ayarlar", "carryon.category.settings": "Ayarlar",
"carryon.category.blacklist": "Kara Liste", "carryon.category.blacklist": "Kara Liste",
"carryon.category.modeloverrides": "Modellerin Üzerine Yaz (Gelişmiş)", "carryon.category.modeloverrides": "Üzerine Yazılan Modeller (Gelişmiş)",
"carryon.category.custompickupconditions": "Özel Yerden Alma Durumları (Gelişmiş)", "carryon.category.custompickupconditions": "Özel Yerden Alma Durumları (Gelişmiş)",
"carryon.category.whitelist": "Beyaz Liste", "carryon.category.whitelist": "Beyaz Liste",
@ -12,6 +12,6 @@
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Özel Blok Alma Durumları", "carryon.category.custompickupconditions.custompickupconditionsblocks": "Özel Blok Alma Durumları",
"carryon.category.custompickupconditions.custompickupconditionsentities": "Özel Varlık Alma Durumları", "carryon.category.custompickupconditions.custompickupconditionsentities": "Özel Varlık Alma Durumları",
"key.carry.desc": "Taşı Taşı", "key.carry.desc": "Taşı",
"key.carry.category": "Taşımaya Devam Et" "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

@ -2,15 +2,18 @@
"required": true, "required": true,
"minVersion": "0.8", "minVersion": "0.8",
"package": "tschipp.carryon.mixin", "package": "tschipp.carryon.mixin",
"compatibilityLevel": "JAVA_17", "compatibilityLevel": "JAVA_21",
"mixins": [ "mixins": [
"EntityMixin", "EntityMixin",
"InventoryMixin", "InventoryMixin",
"PlayerMixin" "PlayerMixin"
], ],
"client": [ "client": [
"AvatarRendererMixin",
"EntityRendererMixin",
"HumanoidModelMixin", "HumanoidModelMixin",
"MinecraftMixin" "MinecraftMixin",
"PlayerRenderStateMixin"
], ],
"server": [ "server": [
], ],
@ -18,5 +21,5 @@
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1
}, },
"refmap": "${refmap_target}refmap.json" "refmap": "${mod_id}.refmap.json"
} }

View File

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

View File

@ -1,28 +1,24 @@
plugins { plugins {
id 'fabric-loom' version '1.0-SNAPSHOT' id 'multiloader-loader'
id 'maven-publish' id 'fabric-loom' version "${loom_version}"
id 'idea'
} }
archivesBaseName = "${mod_id}-fabric-${minecraft_version}"
apply from: 'https://raw.githubusercontent.com/MinecraftModDevelopment/Gradle-Collection/22e7d543a18cd30675277fbfa3669e3d9e206010/generic/secrets.gradle'
if (project.hasProperty('secretFile')) {
loadSecrets(new File((String) findProperty('secretFile')))
}
if (System.getenv('BUILD_NUMBER') != null) {
version += "." + System.getenv('BUILD_NUMBER')
}
repositories { repositories {
maven { url 'https://jitpack.io' }
maven { maven {
url "https://maven.siphalor.de/" name = "Shedaniel"
name "Siphalor's Maven" url "https://maven.shedaniel.me/"
}
maven { url 'https://jitpack.io' }
maven {
name = "Terraformers"
url = "https://maven.terraformersmc.com/"
} }
} }
dependencies { dependencies {
minecraft "com.mojang:minecraft:${minecraft_version}" minecraft "com.mojang:minecraft:${minecraft_version}"
mappings loom.layered() { mappings loom.layered() {
@ -32,15 +28,21 @@ dependencies {
modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}" modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}"
implementation group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.1' implementation group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.1'
implementation project(":Common")
include implementation("com.github.llamalad7.mixinextras:mixinextras-fabric:${mixinextras_version}")
annotationProcessor("com.github.llamalad7.mixinextras:mixinextras-fabric:${mixinextras_version}")
modImplementation "de.siphalor:amecsapi-1.19:1.3.9+mc1.19.4" modApi("me.shedaniel.cloth:cloth-config-fabric:${cloth_config_version}") {
include "de.siphalor:amecsapi-1.19:1.3.9+mc1.19.4" exclude(group: "net.fabricmc.fabric-api")
}
modApi "com.terraformersmc:modmenu:17.0.0-beta.1"
} }
loom { 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 { runs {
client { client {
client() client()
@ -56,41 +58,3 @@ loom {
} }
} }
} }
var refmap_target = archivesBaseName + "-"
processResources {
from project(":Common").sourceSets.main.resources
inputs.property "version", project.version
inputs.property "refmap_target", refmap_target
filesMatching("fabric.mod.json") {
expand "version": project.version
}
filesMatching("carryon.mixins.json") {
expand "refmap_target": refmap_target
}
}
tasks.withType(JavaCompile) {
source(project(":Common").sourceSets.main.allSource)
}
publishing {
publications {
mavenJava(MavenPublication) {
groupId project.group
artifactId project.archivesBaseName
version project.version
from components.java
}
}
repositories {
maven {
url "file://" + System.getenv("local_maven")
}
}
}

View File

@ -1,18 +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; package tschipp.carryon;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import tschipp.carryon.client.keybinds.CarryOnKeybinds; import tschipp.carryon.client.keybinds.CarryOnKeybinds;
import tschipp.carryon.events.ClientEvents; import tschipp.carryon.events.ClientEvents;
import tschipp.carryon.networking.PacketBase; import tschipp.carryon.networking.PacketBase;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Function;
public class CarryOnFabricClientMod implements ClientModInitializer public class CarryOnFabricClientMod implements ClientModInitializer
{ {
@ -21,22 +38,19 @@ public class CarryOnFabricClientMod implements ClientModInitializer
{ {
CarryOnKeybinds.registerKeybinds(KeyBindingHelper::registerKeyBinding); CarryOnKeybinds.registerKeybinds(KeyBindingHelper::registerKeyBinding);
ClientEvents.registerEvents(); ClientEvents.registerEvents();
CarryOnCommon.registerClientPackets(); CarryOnCommon.registerClientPackets(true);
} }
public static void sendPacketToServer(ResourceLocation id, PacketBase packet) public static void sendPacketToServer(PacketBase packet)
{ {
FriendlyByteBuf buf = PacketByteBufs.create(); ClientPlayNetworking.send(packet);
packet.toBytes(buf);
ClientPlayNetworking.send(id, buf);
} }
public static <T extends PacketBase> void registerClientboundPacket(ResourceLocation id, Function<FriendlyByteBuf, T> reader, BiConsumer<T, Player> handler) public static <T extends PacketBase> void registerClientboundPacket(CustomPacketPayload.Type<T> id, BiConsumer<T, Player> handler)
{ {
ClientPlayNetworking.registerGlobalReceiver(id, (client, packetHandler, buf, responseSender) -> { ClientPlayNetworking.registerGlobalReceiver(id, (T packet, ClientPlayNetworking.Context context) -> {
T packet = reader.apply(buf); context.client().execute(() -> {
client.execute(() -> { handler.accept(packet, context.player());
handler.accept(packet, client.player);
}); });
}); });
} }

View File

@ -1,13 +1,56 @@
/*
* 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; package tschipp.carryon;
import net.fabricmc.api.ModInitializer; 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.config.fabric.ConfigLoaderImpl;
import tschipp.carryon.events.CommonEvents; import tschipp.carryon.events.CommonEvents;
import java.io.IOException; import java.io.IOException;
public class CarryOnFabricMod implements ModInitializer { 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 @Override
public void onInitialize() { public void onInitialize() {
@ -25,6 +68,7 @@ public class CarryOnFabricMod implements ModInitializer {
CommonEvents.registerEvents(); CommonEvents.registerEvents();
CarryOnCommon.registerServerPackets(); CarryOnCommon.registerServerPackets();
CarryOnCommon.registerClientPackets(false);
} }
} }

View File

@ -1,6 +1,25 @@
/*
* 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; package tschipp.carryon.compat;
import net.fabricmc.fabric.api.event.Event;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@ -19,6 +38,7 @@ public class ArchitecturyCompat {
private static Method PLACE_BLOCK; private static Method PLACE_BLOCK;
private static Method IS_FALSE; private static Method IS_FALSE;
@SuppressWarnings("unchecked")
private static void setup( ) { private static void setup( ) {
try { try {
Class BlockEvent = Class.forName("dev.architectury.event.events.common.BlockEvent"); Class BlockEvent = Class.forName("dev.architectury.event.events.common.BlockEvent");

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

@ -1,8 +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.fabric; package tschipp.carryon.config.fabric;
import com.google.gson.*; import com.google.gson.*;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import tschipp.carryon.common.config.ListHandler;
import tschipp.carryon.config.*; import tschipp.carryon.config.*;
import java.io.File; import java.io.File;
@ -10,7 +31,7 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -19,7 +40,7 @@ public class ConfigLoaderImpl {
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create(); private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
//Default JSON and config data. //Default JSON and config data.
public static final Map<JsonObject, BuiltConfig> CONFIGS = new HashMap<>(); public static final Map<JsonObject, BuiltConfig> CONFIGS = new LinkedHashMap<>();
public static void initialize() throws IOException { public static void initialize() throws IOException {
Path cfgPath = FabricLoader.getInstance().getConfigDir(); Path cfgPath = FabricLoader.getInstance().getConfigDir();
@ -48,11 +69,11 @@ public class ConfigLoaderImpl {
JsonElement value = entry.getValue(); JsonElement value = entry.getValue();
if (value instanceof JsonPrimitive configValue) { if (value instanceof JsonPrimitive configValue) {
category.getProperty(id).ifPresent(data -> { category.getProperty(id).ifPresent(data -> {
if (configValue.isBoolean() && data.data().type().equals(PropertyType.BOOLEAN)) if (configValue.isBoolean() && data.getData().type().equals(PropertyType.BOOLEAN))
data.setBoolean(configValue.getAsBoolean()); data.setBoolean(configValue.getAsBoolean());
if (configValue.isNumber() && data.data().type().equals(PropertyType.INT)) { if (configValue.isNumber() && data.getData().type().equals(PropertyType.INT)) {
int configInt = configValue.getAsInt(); int configInt = configValue.getAsInt();
if (configInt > data.data().max() || configInt < data.data().min()) { if (configInt > data.getData().max() || configInt < data.getData().min()) {
try { try {
config.addProperty(id, data.getInt()); config.addProperty(id, data.getInt());
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
@ -61,9 +82,9 @@ public class ConfigLoaderImpl {
data.setInt(configInt); data.setInt(configInt);
} }
} }
if (configValue.isNumber() && data.data().type().equals(PropertyType.DOUBLE)) { if (configValue.isNumber() && data.getData().type().equals(PropertyType.DOUBLE)) {
double configDouble = configValue.getAsDouble(); double configDouble = configValue.getAsDouble();
if (configDouble > data.data().maxD() || configDouble < data.data().minD()) { if (configDouble > data.getData().maxD() || configDouble < data.getData().minD()) {
try { try {
config.addProperty(id, data.getDouble()); config.addProperty(id, data.getDouble());
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
@ -77,7 +98,7 @@ public class ConfigLoaderImpl {
category.getCategory(id).ifPresent(cat -> loadConfig(cat, subConfig)); category.getCategory(id).ifPresent(cat -> loadConfig(cat, subConfig));
} else if (value instanceof JsonArray list) { } else if (value instanceof JsonArray list) {
category.getProperty(id).ifPresent(data -> { category.getProperty(id).ifPresent(data -> {
if(data.data().type() == PropertyType.STRING_ARRAY) if(data.getData().type() == PropertyType.STRING_ARRAY)
{ {
List<String> ls = new ArrayList<>(); List<String> ls = new ArrayList<>();
for(JsonElement arrEle : list) for(JsonElement arrEle : list)
@ -96,6 +117,20 @@ public class ConfigLoaderImpl {
return config; 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) { public static void registerConfig(BuiltConfig config) {
try { try {
JsonObject configJson = new JsonObject(); JsonObject configJson = new JsonObject();
@ -115,21 +150,39 @@ public class ConfigLoaderImpl {
builder.add(category.category, categoryJson); builder.add(category.category, categoryJson);
} }
@SuppressWarnings("unchecked")
private static void buildProperty(JsonObject builder, PropertyData data) throws IllegalAccessException { private static void buildProperty(JsonObject builder, PropertyData data) throws IllegalAccessException {
AnnotationData annotationData = data.data(); AnnotationData annotationData = data.getData();
builder.addProperty("//"+data.getId(), annotationData.description()); builder.addProperty("//"+data.getId(), annotationData.description());
switch (annotationData.type()) { switch (annotationData.type()) {
case BOOLEAN -> builder.addProperty(data.getId(), data.getBoolean()); case BOOLEAN:
case INT -> builder.addProperty(data.getId(), data.getInt()); builder.addProperty(data.getId(), data.getBoolean());
case DOUBLE -> builder.addProperty(data.getId(), data.getDouble()); data.setSetter((b) -> {builder.addProperty(data.getId(), (boolean)b); data.setBoolean((boolean)b);});
case STRING_ARRAY -> { 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(); JsonArray arr = new JsonArray();
for(String s : data.getStringArray()) for(String s : data.getStringArray())
arr.add(s); arr.add(s);
builder.add(data.getId(), arr); builder.add(data.getId(), arr);
} data.setSetter(list -> {
default -> throw new IllegalAccessException("Unknown property type."); 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

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.events;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;

View File

@ -1,11 +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.events; package tschipp.carryon.events;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; 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.entity.event.v1.ServerPlayerEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.CommonLifecycleEvents; 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.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.event.player.*; import net.fabricmc.fabric.api.event.player.*;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
@ -29,12 +51,12 @@ public class CommonEvents {
CommonLifecycleEvents.TAGS_LOADED.register((registries, client) -> { CommonLifecycleEvents.TAGS_LOADED.register((registries, client) -> {
if(!client) if(!client)
ConfigLoader.onConfigLoaded(); ConfigLoader.onConfigLoaded(registries);
}); });
UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> { UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> {
if(world.isClientSide) if(world.isClientSide())
return InteractionResult.PASS; return InteractionResult.PASS;
BlockPos pos = hitResult.getBlockPos(); BlockPos pos = hitResult.getBlockPos();
@ -75,7 +97,7 @@ public class CommonEvents {
UseEntityCallback.EVENT.register((player, level, hand, entity, hitResult) -> { UseEntityCallback.EVENT.register((player, level, hand, entity, hitResult) -> {
if(level.isClientSide) if(level.isClientSide())
return InteractionResult.PASS; return InteractionResult.PASS;
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
@ -111,12 +133,10 @@ public class CommonEvents {
CarryOnCommon.onCarryTick(player); CarryOnCommon.onCarryTick(player);
}); });
ServerPlayerEvents.COPY_FROM.register(((oldPlayer, newPlayer, alive) -> { ServerPlayerEvents.COPY_FROM.register(((oldPlayer, newPlayer, alive) -> {
PlacementHandler.placeCarriedOnDeath(oldPlayer, newPlayer, !alive); PlacementHandler.placeCarriedOnDeath(oldPlayer, newPlayer, !alive);
})); }));
PlayerBlockBreakEvents.BEFORE.register(((world, player, pos, state, blockEntity) -> { PlayerBlockBreakEvents.BEFORE.register(((world, player, pos, state, blockEntity) -> {
if(!CarryOnCommon.onTryBreakBlock(player)) if(!CarryOnCommon.onTryBreakBlock(player))
return false; return false;
@ -135,7 +155,23 @@ public class CommonEvents {
return InteractionResult.PASS; return InteractionResult.PASS;
})); }));
//TODO: drop carried when attacked 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

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.mixin;

View File

@ -1,31 +1,44 @@
/*
* 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; package tschipp.carryon.mixin;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.AbstractClientPlayer; import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.ItemInHandRenderer; import net.minecraft.client.renderer.ItemInHandRenderer;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.RenderBuffers;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import tschipp.carryon.client.render.CarriedObjectRender; import tschipp.carryon.client.render.CarriedObjectRender;
import tschipp.carryon.client.render.CarryRenderHelper;
import tschipp.carryon.platform.Services;
@Mixin(ItemInHandRenderer.class) @Mixin(ItemInHandRenderer.class)
public class ItemInHandRendererMixin 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/MultiBufferSource;I)V", cancellable = true) @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 onRenderHand(AbstractClientPlayer player, float partialTicks, float pitch, InteractionHand hand, float pSwingProgress, ItemStack pStack, float pEquippedProgress, PoseStack poseStack, MultiBufferSource buffer, int light, CallbackInfo ci) 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(CarryRenderHelper.getPerspective() == 0 && CarriedObjectRender.drawFirstPerson(player, buffer, poseStack, light, partialTicks)) if(CarriedObjectRender.draw(player, poseStack, packedLight, partialTick,nodeCollector,true))
ci.cancel(); ci.cancel();
} }

View File

@ -1,23 +0,0 @@
package tschipp.carryon.mixin;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Camera;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.LightTexture;
import org.joml.Matrix4f;
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(LevelRenderer.class)
public class LevelRendererMixin
{
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/ParticleEngine;render(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;Lnet/minecraft/client/renderer/LightTexture;Lnet/minecraft/client/Camera;F)V"), method = "Lnet/minecraft/client/renderer/LevelRenderer;renderLevel(Lcom/mojang/blaze3d/vertex/PoseStack;FJZLnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/GameRenderer;Lnet/minecraft/client/renderer/LightTexture;Lorg/joml/Matrix4f;)V")
private void onRenderLevel(PoseStack poseStack, float f, long l, boolean bl, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f matrix4f, CallbackInfo ci)
{
CarriedObjectRender.drawThirdPerson(gameRenderer.getMinecraft().getFrameTime(), poseStack);
}
}

View File

@ -1,5 +1,26 @@
/*
* 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; package tschipp.carryon.mixin;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
@ -15,13 +36,13 @@ import tschipp.carryon.common.carry.PlacementHandler;
@Mixin(Player.class) @Mixin(Player.class)
public class PlayerMixinFabric public class PlayerMixinFabric
{ {
@Inject(at = @At("HEAD"), method = "hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z") @Inject(at = @At("HEAD"), method = "hurtServer(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/damagesource/DamageSource;F)Z")
private void onHurt(DamageSource damageSource, float f, CallbackInfoReturnable<Boolean> cir) { private void onHurt(ServerLevel level, DamageSource damageSource, float amount, CallbackInfoReturnable<Boolean> cir) {
if(Constants.COMMON_CONFIG.settings.dropCarriedWhenHit) if(Constants.COMMON_CONFIG.settings.dropCarriedWhenHit)
{ {
Player player = ((Player)(Object)this); Player player = ((Player)(Object)this);
CarryOnData carry = CarryOnDataManager.getCarryData(player); CarryOnData carry = CarryOnDataManager.getCarryData(player);
if(carry.isCarrying() && !player.level.isClientSide) if(carry.isCarrying())
PlacementHandler.placeCarried((ServerPlayer)player); PlacementHandler.placeCarried((ServerPlayer)player);
} }

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.mixin;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@ -14,9 +34,10 @@ import tschipp.carryon.common.carry.CarryOnDataManager;
@Mixin(Screen.class) @Mixin(Screen.class)
public class ScreenMixin public class ScreenMixin
{ {
@Inject(at = @At(value = "TAIL"), method = "init(Lnet/minecraft/client/Minecraft;II)V") @Inject(at = @At(value = "TAIL"), method = "init(II)V")
private void onInit(Minecraft mc, int i, int j, CallbackInfo ci) private void onInit(int width, int height, CallbackInfo ci)
{ {
Minecraft mc = Minecraft.getInstance();
Player player = mc.player; Player player = mc.player;
if((Object)this instanceof AbstractContainerScreen && player != null) if((Object)this instanceof AbstractContainerScreen && player != null)
{ {

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.platform;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;

View File

@ -1,20 +1,44 @@
/*
* 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; package tschipp.carryon.platform;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation; 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.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import tschipp.carryon.CarryOnFabricClientMod; import tschipp.carryon.CarryOnFabricClientMod;
import tschipp.carryon.CarryOnFabricMod;
import tschipp.carryon.common.carry.CarryOnData;
import tschipp.carryon.config.BuiltConfig; import tschipp.carryon.config.BuiltConfig;
import tschipp.carryon.config.fabric.ConfigLoaderImpl; import tschipp.carryon.config.fabric.ConfigLoaderImpl;
import tschipp.carryon.networking.PacketBase; import tschipp.carryon.networking.PacketBase;
import tschipp.carryon.platform.services.IPlatformHelper; import tschipp.carryon.platform.services.IPlatformHelper;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Function;
public class FabricPlatformHelper implements IPlatformHelper { public class FabricPlatformHelper implements IPlatformHelper {
@ -40,34 +64,51 @@ public class FabricPlatformHelper implements IPlatformHelper {
ConfigLoaderImpl.registerConfig(cfg); ConfigLoaderImpl.registerConfig(cfg);
} }
@SuppressWarnings("unchecked")
@Override @Override
public <T extends PacketBase> void registerServerboundPacket(ResourceLocation id, int numericalId, Class<T> clazz, BiConsumer<T, FriendlyByteBuf> writer, Function<FriendlyByteBuf, T> reader, BiConsumer<T, Player> handler) 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)
{ {
ServerPlayNetworking.registerGlobalReceiver(id, (server, player, packetHandler, buf, responseSender) -> { PayloadTypeRegistry.playC2S().register(type, (StreamCodec<RegistryFriendlyByteBuf, T>)codec);
T packet = reader.apply(buf);
server.execute(() -> { ServerPlayNetworking.registerGlobalReceiver(type, (T packet, ServerPlayNetworking.Context context) -> {
handler.accept(packet, player); context.server().execute(() -> {
handler.accept(packet, context.player());
}); });
}); });
} }
@SuppressWarnings("unchecked")
@Override @Override
public <T extends PacketBase> void registerClientboundPacket(ResourceLocation id, int numericalId, Class<T> clazz, BiConsumer<T, FriendlyByteBuf> writer, Function<FriendlyByteBuf, T> reader, BiConsumer<T, Player> handler) 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)
{ {
CarryOnFabricClientMod.registerClientboundPacket(id, reader, handler); boolean client = (boolean)args[0];
if(!client)
PayloadTypeRegistry.playS2C().register(type, (StreamCodec<RegistryFriendlyByteBuf, T>)codec);
else
CarryOnFabricClientMod.registerClientboundPacket(type, handler);
} }
@Override @Override
public void sendPacketToServer(ResourceLocation id, PacketBase packet) public void sendPacketToServer(Identifier id, PacketBase packet)
{ {
CarryOnFabricClientMod.sendPacketToServer(id, packet); CarryOnFabricClientMod.sendPacketToServer(packet);
} }
@Override @Override
public void sendPacketToPlayer(ResourceLocation id, PacketBase packet, ServerPlayer player) public void sendPacketToPlayer(Identifier id, PacketBase packet, ServerPlayer player)
{ {
FriendlyByteBuf buf = PacketByteBufs.create(); ServerPlayNetworking.send(player, packet);
packet.toBytes(buf); }
ServerPlayNetworking.send(player, id, buf);
@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

@ -1,15 +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; package tschipp.carryon.scripting;
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.Identifier;
import tschipp.carryon.Constants; import tschipp.carryon.Constants;
import tschipp.carryon.common.scripting.ScriptReloadListener; import tschipp.carryon.common.scripting.ScriptReloadListener;
public class IdentifiableScriptReloadListener extends ScriptReloadListener implements IdentifiableResourceReloadListener public class IdentifiableScriptReloadListener extends ScriptReloadListener implements IdentifiableResourceReloadListener
{ {
@Override @Override
public ResourceLocation getFabricId() public Identifier getFabricId()
{ {
return new ResourceLocation(Constants.MOD_ID, "carryon_scripts"); return Identifier.fromNamespaceAndPath(Constants.MOD_ID, "carryon_scripts");
} }
} }

View File

@ -2,14 +2,13 @@
"required": true, "required": true,
"minVersion": "0.8", "minVersion": "0.8",
"package": "tschipp.carryon.mixin", "package": "tschipp.carryon.mixin",
"compatibilityLevel": "JAVA_17", "compatibilityLevel": "JAVA_21",
"mixins": [ "mixins": [
"PlayerMixinFabric" "PlayerMixinFabric"
], ],
"client": [ "client": [
"ItemInHandRendererMixin", "ItemInHandRendererMixin",
"LevelRendererMixin", "ScreenMixin"
"ScreenMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1

View File

@ -1,11 +1,11 @@
{ {
"schemaVersion": 1, "schemaVersion": 1,
"id": "carryon", "id": "${mod_id}",
"version": "${version}", "version": "${version}",
"name": "Carry On", "name": "${mod_name}",
"description": "Carry On is a simple mod that improves game interaction by allowing players to pick up, carry, and place single block Tile Entities using only their empty hands.", "description": "${description}",
"authors": [ "authors": [
"Tschipp", "Purplicious_Cow", "cy4n" "Tschipp", "Purplicious_Cow"
], ],
"contact": { "contact": {
"homepage": "https://tschipp.ch/", "homepage": "https://tschipp.ch/",
@ -13,7 +13,7 @@
"issues": "https://github.com/Tschipp/CarryOn/issues" "issues": "https://github.com/Tschipp/CarryOn/issues"
}, },
"license": "GNU LGPLv3", "license": "${license}",
"icon": "logo.png", "icon": "logo.png",
"environment": "*", "environment": "*",
@ -23,6 +23,9 @@
], ],
"client": [ "client": [
"tschipp.carryon.CarryOnFabricClientMod" "tschipp.carryon.CarryOnFabricClientMod"
],
"modmenu" : [
"tschipp.carryon.compat.ModMenuCompat"
] ]
}, },
"mixins": [ "mixins": [
@ -31,10 +34,10 @@
], ],
"depends": { "depends": {
"fabricloader": ">=0.14", "fabricloader": ">=${fabric_loader_version}",
"fabric-api": "*", "fabric-api": "*",
"minecraft": ">=1.19.3", "minecraft": "${minecraft_version_range_fabric}",
"java": ">=17" "java": ">=${java_version}"
} }
} }

View File

@ -1,38 +1,13 @@
buildscript { plugins {
repositories { id 'multiloader-loader'
maven { url = 'https://maven.minecraftforge.net' } id 'net.minecraftforge.gradle' version '[6.0.46,6.2)'
maven { url = 'https://repo.spongepowered.org/repository/maven-public/' } id 'org.spongepowered.mixin' version '0.7-SNAPSHOT'
maven { url = 'https://maven.parchmentmc.org' } id 'org.parchmentmc.librarian.forgegradle' version '1.+'
mavenCentral()
gradlePluginPortal()
}
dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true
classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT'
classpath 'org.parchmentmc:librarian:1.+'
classpath 'gradle.plugin.com.github.johnrengelman:shadow:7.1.2'
}
}
apply plugin: 'java'
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'eclipse'
apply plugin: 'org.spongepowered.mixin'
apply plugin: 'maven-publish'
apply plugin: 'org.parchmentmc.librarian.forgegradle'
apply plugin: 'com.github.johnrengelman.shadow'
apply from: 'https://raw.githubusercontent.com/MinecraftModDevelopment/Gradle-Collection/22e7d543a18cd30675277fbfa3669e3d9e206010/generic/secrets.gradle'
if (project.hasProperty('secretFile')) {
loadSecrets(new File((String) findProperty('secretFile')))
}
if (System.getenv('BUILD_NUMBER') != null) {
version += "." + System.getenv('BUILD_NUMBER')
} }
jarJar.enable() base {
archivesName = "${mod_id}-forge-${minecraft_version}"
archivesBaseName = "${mod_id}-forge-${minecraft_version}" }
mixin { mixin {
add sourceSets.main, "${mod_id}.refmap.json" add sourceSets.main, "${mod_id}.refmap.json"
@ -41,14 +16,25 @@ mixin {
config "${mod_id}.forge.mixins.json" config "${mod_id}.forge.mixins.json"
} }
tasks.named('jar', Jar).configure {
manifest {
attributes([
"MixinConfigs" : "${mod_id}.mixins.json,${mod_id}.forge.mixins.json"
])
}
}
jarJar.enable()
build.dependsOn tasks.jarJar
minecraft { minecraft {
mappings channel: 'parchment', version: "${parchment_mappings}" mappings channel: 'parchment', version: parchment_mappings
copyIdeResources = true
if (project.hasProperty('forge_ats_enabled') && project.findProperty('forge_ats_enabled').toBoolean()) { reobf = false
// This location is hardcoded in Forge and can not be changed.
// https://github.com/MinecraftForge/MinecraftForge/blob/be1698bb1554f9c8fa2f58e32b9ab70bc4385e60/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java#L123 def at = file('src/main/resources/META-INF/accesstransformer.cfg')
accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') if (at.exists()) {
project.logger.debug('Forge Access Transformers are enabled for this project.') accessTransformer = at
} }
runs { runs {
@ -58,6 +44,7 @@ minecraft {
taskName 'Client' taskName 'Client'
property 'mixin.env.remapRefMap', 'true' property 'mixin.env.remapRefMap', 'true'
property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"
property 'eventbus.api.strictRuntimeChecks', 'true'
args "-mixin.config=${mod_id}.mixins.json", "-mixin.config=${mod_id}.forge.mixins.json" args "-mixin.config=${mod_id}.mixins.json", "-mixin.config=${mod_id}.forge.mixins.json"
mods { mods {
modClientRun { modClientRun {
@ -73,6 +60,7 @@ minecraft {
taskName 'Server' taskName 'Server'
property 'mixin.env.remapRefMap', 'true' property 'mixin.env.remapRefMap', 'true'
property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"
property 'eventbus.api.strictRuntimeChecks', 'true'
args "-mixin.config=${mod_id}.mixins.json", "-mixin.config=${mod_id}.forge.mixins.json" args "-mixin.config=${mod_id}.mixins.json", "-mixin.config=${mod_id}.forge.mixins.json"
mods { mods {
modServerRun { modServerRun {
@ -89,6 +77,7 @@ minecraft {
taskName 'Data' taskName 'Data'
property 'mixin.env.remapRefMap', 'true' property 'mixin.env.remapRefMap', 'true'
property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"
property 'eventbus.api.strictRuntimeChecks', 'true'
args "-mixin.config=${mod_id}.mixins.json", "-mixin.config=${mod_id}.forge.mixins.json" args "-mixin.config=${mod_id}.mixins.json", "-mixin.config=${mod_id}.forge.mixins.json"
mods { mods {
modDataRun { modDataRun {
@ -104,68 +93,59 @@ sourceSets.main.resources.srcDir 'src/generated/resources'
repositories { repositories {
maven { maven {
url 'https://maven.blamejared.com' name = "Shedaniel"
url "https://maven.shedaniel.me/"
} }
maven { url 'https://jitpack.io' }
flatDir { flatDir {
dirs 'libs' dirs 'libs'
} }
maven { url 'https://jitpack.io' }
} }
dependencies { dependencies {
minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
compileOnly project(":Common") compileOnly project(":Common")
implementation(annotationProcessor("com.github.llamalad7.mixinextras:mixinextras-common:${mixinextras_version}")) annotationProcessor 'org.spongepowered:mixin:0.8.5-SNAPSHOT:processor'
implementation(jarJar("com.github.llamalad7.mixinextras:mixinextras-forge:${mixinextras_version}")) { annotationProcessor 'net.minecraftforge:eventbus-validator:7.0-beta.7'
// Hack fix for now, force jopt-simple to be exactly 5.0.4 because Mojang ships that version, but some transitive dependencies request 6.0+
implementation('net.sf.jopt-simple:jopt-simple:5.0.4') { version { strictly '5.0.4' } }
testCompileOnly(compileOnly(annotationProcessor("io.github.llamalad7:mixinextras-common:${mixinextras_version}")))
implementation(jarJar("io.github.llamalad7:mixinextras-forge:${mixinextras_version}")) {
jarJar.ranged(it, "[${mixinextras_version},)") jarJar.ranged(it, "[${mixinextras_version},)")
} }
//implementation fg.deobf("net.darkhax.gamestages:GameStages-Forge-1.19.2:11.0.2") //implementation fg.deobf("net.darkhax.gamestages:GameStages-Forge-1.19.2:11.0.2")
//implementation fg.deobf("net.darkhax.bookshelf:Bookshelf-Forge-1.19.3:17.0.2")
annotationProcessor 'org.spongepowered:mixin:0.8.4-SNAPSHOT:processor' compileOnly(fg.deobf("me.shedaniel.cloth:cloth-config-neoforge:${cloth_config_version}"))
fileTree("libs").matching { fileTree("libs").matching {
include "*.jar" include "*.jar"
}.each { }.each {
String filename = it.getName(); String filename = it.getName();
filename = filename.substring(0, filename.length() - 4); filename = filename.substring(0, filename.length() - 4);
int lastDash = filename.lastIndexOf("-"); int lastDash = filename.lastIndexOf("-");
filename = filename.substring(0, lastDash) + ":" + filename.substring(lastDash+1, filename.length()); filename = filename.substring(0, lastDash) + ":" + filename.substring(lastDash+1, filename.length());
implementation fg.deobf("blank:${filename}") implementation fg.deobf("blank:${filename}")
} }
} }
reobf {
jarJar {}
}
tasks.withType(JavaCompile) {
source(project(":Common").sourceSets.main.allSource)
}
processResources {
from project(":Common").sourceSets.main.resources
filesMatching('*.mixins.json') {
expand "refmap_target": "${mod_id}."
}
}
jar.finalizedBy('reobfJar')
publishing { publishing {
publications { publications {
mavenJava(MavenPublication) { mavenJava(MavenPublication) {
groupId project.group fg.component(it)
artifactId project.archivesBaseName
version project.version
artifact jar
}
}
repositories {
maven {
url "file://" + System.getenv("local_maven")
} }
} }
} }
sourceSets.each {
def dir = layout.buildDirectory.dir("sourcesSets/$it.name")
it.output.resourcesDir = dir
it.java.destinationDirectory = dir
}

View File

@ -1,14 +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; package tschipp.carryon;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.Identifier;
import net.minecraftforge.fml.InterModComms; import net.minecraftforge.eventbus.api.listener.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.ChannelBuilder;
import net.minecraftforge.network.simple.SimpleChannel; import net.minecraftforge.network.SimpleChannel;
import tschipp.carryon.config.forge.ConfigLoaderImpl; import tschipp.carryon.config.forge.ConfigLoaderImpl;
import tschipp.carryon.networking.ClientboundSyncCarryDataPacket;
import tschipp.carryon.platform.Services;
@Mod(Constants.MOD_ID) @Mod(Constants.MOD_ID)
@EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) @EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
@ -16,7 +38,7 @@ public class CarryOnForge {
public static SimpleChannel network; public static SimpleChannel network;
public CarryOnForge() { public CarryOnForge(FMLJavaModLoadingContext context) {
// This method is invoked by the Forge mod loader when it is ready // This method is invoked by the Forge mod loader when it is ready
// to load your mod. You can access Forge and Common code in this // to load your mod. You can access Forge and Common code in this
@ -24,17 +46,23 @@ public class CarryOnForge {
// Use Forge to bootstrap the Common mod. // Use Forge to bootstrap the Common mod.
CarryOnCommon.registerConfig(); CarryOnCommon.registerConfig();
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup); ConfigLoaderImpl.initialize(context);
ConfigLoaderImpl.initialize();
} }
private void setup(final FMLCommonSetupEvent event) @SubscribeEvent
public static void setup(final FMLCommonSetupEvent event)
{ {
network = NetworkRegistry.newSimpleChannel(new ResourceLocation(Constants.MOD_ID, "carryonpackets"), () -> "1.0", "1.0"::equals, "1.0"::equals); network = ChannelBuilder.named(Identifier.fromNamespaceAndPath(Constants.MOD_ID, "carryonpackets")).simpleChannel();
CarryOnCommon.registerServerPackets(); CarryOnCommon.registerServerPackets();
CarryOnCommon.registerClientPackets(); CarryOnCommon.registerClientPackets();
Services.PLATFORM.registerClientboundPacket(
ClientboundSyncCarryDataPacket.TYPE,
ClientboundSyncCarryDataPacket.class,
ClientboundSyncCarryDataPacket.CODEC,
ClientboundSyncCarryDataPacket::handle
);
} }
} }

View File

@ -0,0 +1,23 @@
package tschipp.carryon.carry;
import net.minecraft.nbt.CompoundTag;
import tschipp.carryon.common.carry.CarryOnData;
public class CarryOnDataCapability implements ICarryOnDataCapability {
private CarryOnData data;
public CarryOnDataCapability() {
this.data = new CarryOnData(new CompoundTag());
}
@Override
public CarryOnData getCarryData() {
return data;
}
@Override
public void setCarryData(CarryOnData data) {
this.data = data;
}
}

View File

@ -0,0 +1,38 @@
package tschipp.carryon.carry;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.CapabilityToken;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.LazyOptional;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import tschipp.carryon.common.carry.CarryOnData;
public class CarryOnDataCapabilityProvider implements ICapabilitySerializable<CompoundTag> {
public static final Capability<ICarryOnDataCapability> CARRY_ON_DATA_CAPABILITY = CapabilityManager.get(new CapabilityToken<ICarryOnDataCapability>() {});
private final CarryOnDataCapability impl = new CarryOnDataCapability();
private final LazyOptional<ICarryOnDataCapability> opt = LazyOptional.of(() -> impl);
@Override
public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
return cap == CARRY_ON_DATA_CAPABILITY ? opt.cast() : LazyOptional.empty();
}
@Override
public CompoundTag serializeNBT(HolderLookup.Provider registryAccess) {
return (CompoundTag) CarryOnData.CODEC.encodeStart(NbtOps.INSTANCE, impl.getCarryData()).getOrThrow();
}
@Override
public void deserializeNBT(HolderLookup.Provider registryAccess, CompoundTag nbt) {
CarryOnData data = CarryOnData.CODEC.parse(NbtOps.INSTANCE, nbt).getOrThrow();
impl.setCarryData(data);
}
}

View File

@ -0,0 +1,13 @@
package tschipp.carryon.carry;
import net.minecraftforge.common.capabilities.AutoRegisterCapability;
import tschipp.carryon.common.carry.CarryOnData;
@AutoRegisterCapability
public interface ICarryOnDataCapability {
CarryOnData getCarryData();
void setCarryData(CarryOnData data);
}

View File

@ -1,3 +1,23 @@
/*
* 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; package tschipp.carryon.compat;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;

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