Compare commits
246 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de388366ca | ||
|
|
b66040bf03 | ||
|
|
47910dbf61 | ||
|
|
f147e801cc | ||
|
|
20a40c1487 | ||
|
|
08bc465d82 | ||
|
|
3352c497e2 | ||
|
|
f58829ea21 | ||
|
|
550940b4ab | ||
|
|
4ca8a885da | ||
|
|
326880d40b | ||
|
|
d4e0b29a06 | ||
|
|
8d8e0dad82 | ||
|
|
e1e122ae9b | ||
|
|
69eb806228 | ||
|
|
08b2a41043 | ||
|
|
6f0c20077a | ||
|
|
21f09b2526 | ||
|
|
9a484df16e | ||
|
|
e79e52cf65 | ||
|
|
d35cb4ed72 | ||
|
|
5cf2e87fe8 | ||
|
|
ef8362e728 | ||
|
|
e3be9c84da | ||
|
|
efdd3277cc | ||
|
|
776d079be0 | ||
|
|
9d6ffc37ca | ||
|
|
af25f681be | ||
|
|
98247bceb2 | ||
|
|
41b518942d | ||
|
|
32db7222b7 | ||
|
|
eadfba05e8 | ||
|
|
00c0c89858 | ||
|
|
59ecfa81e5 | ||
|
|
c4346a4c00 | ||
|
|
3fddd1112b | ||
|
|
ece3ed7ff2 | ||
|
|
162fc1051d | ||
|
|
e7bf9a4dee | ||
|
|
7f6e41e36a | ||
|
|
d9d25ab598 | ||
|
|
9b2103137f | ||
|
|
7fc80adfe0 | ||
|
|
c662995320 | ||
|
|
0dec5bb175 | ||
|
|
1194370405 | ||
|
|
45a2b32c97 | ||
|
|
d1227d3d87 | ||
|
|
60594ea3bc | ||
|
|
03c2b1fe1c | ||
|
|
43012f8462 | ||
|
|
24c15ffb7b | ||
|
|
67db9798d8 | ||
|
|
a2362104fc | ||
|
|
5cff7411cb | ||
|
|
c803de7920 | ||
|
|
dd149b2472 | ||
|
|
ae260556b2 | ||
|
|
7251cbf03f | ||
|
|
230692baf6 | ||
|
|
be105218fb | ||
|
|
58b0e8fef0 | ||
|
|
93633a05bb | ||
|
|
0b46e57a92 | ||
|
|
1b65095902 | ||
|
|
d653814af9 | ||
|
|
38688ffb85 | ||
|
|
058b547c30 | ||
|
|
01cacce7df | ||
|
|
7ba95504a6 | ||
|
|
74806d011b | ||
|
|
c292eed7af | ||
|
|
9b1e131641 | ||
|
|
5958fa43c1 | ||
|
|
a622cf0452 | ||
|
|
d3ab092d4f | ||
|
|
9a5b09136f | ||
|
|
8b96dab42b | ||
|
|
5271a82b9f | ||
|
|
a4843857cd | ||
|
|
2a9a8703d4 | ||
|
|
2be47d8d53 | ||
|
|
742a9f0ebc | ||
|
|
dd9964b7b2 | ||
|
|
753f19e7b0 | ||
|
|
3cfb59b70a | ||
|
|
02d3b110a3 | ||
|
|
2830bb3a65 | ||
|
|
3fd4c92822 | ||
|
|
d64aaea8f9 | ||
|
|
032c1a943a | ||
|
|
43d990a4db | ||
|
|
8cc0424d46 | ||
|
|
b574f5b509 | ||
|
|
5750880473 | ||
|
|
75ca33bb8d | ||
|
|
196ffb03bf | ||
|
|
08804d435d | ||
|
|
2f2a4a6ca5 | ||
|
|
5fb444a92c | ||
|
|
aa6ba82ae5 | ||
|
|
0d9e6cf32e | ||
|
|
be7c5e891e | ||
|
|
3ee6f8d56a | ||
|
|
dbb7e59b21 | ||
|
|
68341b7ff1 | ||
|
|
a5366a9a2f | ||
|
|
5efb509aea | ||
|
|
ddbd9d3d84 | ||
|
|
e44ff0ea5b | ||
|
|
0f22c9650f | ||
|
|
5c460996ae | ||
|
|
6c30e82dc5 | ||
|
|
1d29f99e7c | ||
|
|
80899ad999 | ||
|
|
dafcf0c0c2 | ||
|
|
2cbff25e0c | ||
|
|
f330646b9d | ||
|
|
50d47ab650 | ||
|
|
a5b619a77c | ||
|
|
b1e6ea2865 | ||
|
|
7cd979d3e7 | ||
|
|
1e1324bcde | ||
|
|
b684df06fa | ||
|
|
7aacc4a524 | ||
|
|
edd98a10f7 | ||
|
|
efe2aef40b | ||
|
|
d8d9427e60 | ||
|
|
67b114149e | ||
|
|
3492b4d52b | ||
|
|
5249002c2c | ||
|
|
3339a68564 | ||
|
|
6da53ee543 | ||
|
|
e836734ca8 | ||
|
|
9d934e8d90 | ||
|
|
1bb75a9b8e | ||
|
|
b0ba88be5e | ||
|
|
ce00fa1f85 | ||
|
|
209a976d4f | ||
|
|
3c516a650f | ||
|
|
3f61e6c5a9 | ||
|
|
b77e9ddd10 | ||
|
|
78402e9cc7 | ||
|
|
e306fdce7d | ||
|
|
49f3990eee | ||
|
|
2d24b3d8ce | ||
|
|
555b484c1a | ||
|
|
191ce26ee4 | ||
|
|
375eb8dcc3 | ||
|
|
cf6a14f5d9 | ||
|
|
e6ace77c39 | ||
|
|
44a1d33f0f | ||
|
|
02c5376979 | ||
|
|
b462098acf | ||
|
|
b2e2070433 | ||
|
|
cc70ed906b | ||
|
|
28c4d4a2f9 | ||
|
|
df6498a236 | ||
|
|
a84cc85fdb | ||
|
|
0d7aa01233 | ||
|
|
50019a4f94 | ||
|
|
6d85b42903 | ||
|
|
ff15f45ea0 | ||
|
|
3a8d938136 | ||
|
|
61aba0c6a0 | ||
|
|
bb9c321a42 | ||
|
|
c2e567e27e | ||
|
|
5e8ce8fc79 | ||
|
|
80adff0ce3 | ||
|
|
a5529fe730 | ||
|
|
9643947f0f | ||
|
|
97c2f4f8a1 | ||
|
|
9bbb1990a9 | ||
|
|
07e5153c40 | ||
|
|
af1012d7a3 | ||
|
|
439e4f05ca | ||
|
|
3d4dab6619 | ||
|
|
171abb8210 | ||
|
|
de2c5326c6 | ||
|
|
1ece990eb0 | ||
|
|
bea813023c | ||
|
|
894568d64a | ||
|
|
4528be263e | ||
|
|
b470478a40 | ||
|
|
c8e79860ad | ||
|
|
ceed903993 | ||
|
|
2820c9fb3b | ||
|
|
c03fab7b19 | ||
|
|
63d7b6dec8 | ||
|
|
fe6a41e3f3 | ||
|
|
b34e09a387 | ||
|
|
65d3f58eaa | ||
|
|
cb5edc3061 | ||
|
|
d3fb8efb45 | ||
|
|
4e30e55f3a | ||
|
|
cda44221f7 | ||
|
|
29a9cffe8c | ||
|
|
bca7534257 | ||
|
|
eff9e1ba21 | ||
|
|
149fe1978e | ||
|
|
9025c53a35 | ||
|
|
66d7af98d8 | ||
|
|
324b055dea | ||
|
|
5ac582566d | ||
|
|
d3e844e6b3 | ||
|
|
934e36ada8 | ||
|
|
97433722fd | ||
|
|
38cf3d6df3 | ||
|
|
f0bb82ddc8 | ||
|
|
3dbd7deb84 | ||
|
|
5ccc660fef | ||
|
|
6884452534 | ||
|
|
7c950301bb | ||
|
|
d8647e8ab8 | ||
|
|
4daed35785 | ||
|
|
3018400e00 | ||
|
|
c2f348b209 | ||
|
|
88794b0986 | ||
|
|
2ea5ad18d3 | ||
|
|
33309b1114 | ||
|
|
275cf81593 | ||
|
|
732e3b48b2 | ||
|
|
da3e2b42ea | ||
|
|
dad395fd39 | ||
|
|
1fe9f3920e | ||
|
|
109dbb92c6 | ||
|
|
424c699f66 | ||
|
|
24ca37414d | ||
|
|
e9f9a1f1d6 | ||
|
|
4d03f52ac2 | ||
|
|
77058317cd | ||
|
|
7dc848f891 | ||
|
|
b4532bd9fa | ||
|
|
386cd5d2f6 | ||
|
|
b59cbd0a25 | ||
|
|
10ea3ae8ea | ||
|
|
6f3fb079c9 | ||
|
|
44e1804527 | ||
|
|
09bcf55da7 | ||
|
|
89961312c9 | ||
|
|
ca5515cf5b | ||
|
|
b69c05fcc2 | ||
|
|
b1d91bf29d | ||
|
|
ebf6f928bc | ||
|
|
c48aeceae4 | ||
|
|
19b4a4ebd8 |
15
.gitattributes
vendored
Normal file
15
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
* text eol=lf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.patch text eol=lf
|
||||||
|
*.java text eol=lf
|
||||||
|
*.gradle text eol=crlf
|
||||||
|
*.png binary
|
||||||
|
*.gif binary
|
||||||
|
*.exe binary
|
||||||
|
*.dll binary
|
||||||
|
*.jar binary
|
||||||
|
*.lzma binary
|
||||||
|
*.zip binary
|
||||||
|
*.pyd binary
|
||||||
|
*.cfg text eol=lf
|
||||||
|
*.jks binary
|
||||||
22
.github/ISSUE_TEMPLATE/blacklist-request.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/blacklist-request.md
vendored
Normal 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
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal 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
|
||||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal 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.
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -5,14 +5,14 @@ bin
|
||||||
.metadata
|
.metadata
|
||||||
.classpath
|
.classpath
|
||||||
.project
|
.project
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# idea
|
# idea
|
||||||
out
|
out
|
||||||
*.ipr
|
*.ipr
|
||||||
*.iws
|
*.iws
|
||||||
*.iml
|
*.iml
|
||||||
.idea
|
.idea/*
|
||||||
|
!.idea/scopes
|
||||||
|
|
||||||
# gradle
|
# gradle
|
||||||
build
|
build
|
||||||
|
|
@ -21,3 +21,7 @@ build
|
||||||
# other
|
# other
|
||||||
eclipse
|
eclipse
|
||||||
run
|
run
|
||||||
|
runs
|
||||||
|
|
||||||
|
# vscode
|
||||||
|
.vscode/*
|
||||||
51
Common/build.gradle
Normal file
51
Common/build.gradle
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
plugins {
|
||||||
|
id 'multiloader-common'
|
||||||
|
id 'net.neoforged.moddev'
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
name = "Shedaniel"
|
||||||
|
url "https://maven.shedaniel.me/"
|
||||||
|
}
|
||||||
|
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
|
}
|
||||||
|
|
||||||
|
neoForge {
|
||||||
|
neoFormVersion = neo_form_version
|
||||||
|
// Automatically enable AccessTransformers if the file exists
|
||||||
|
def at = file('src/main/resources/META-INF/accesstransformer.cfg')
|
||||||
|
if (at.exists()) {
|
||||||
|
accessTransformers.from(at.absolutePath)
|
||||||
|
}
|
||||||
|
parchment {
|
||||||
|
minecraftVersion = parchment_game_version
|
||||||
|
mappingsVersion = parchment_version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly group: 'org.spongepowered', name: 'mixin', version: '0.8.5'
|
||||||
|
// fabric and neoforge both bundle mixinextras, so it is safe to use it in common
|
||||||
|
implementation("io.github.llamalad7:mixinextras-common:${mixinextras_version}")
|
||||||
|
annotationProcessor("io.github.llamalad7:mixinextras-common:${mixinextras_version}")
|
||||||
|
|
||||||
|
compileOnly("me.shedaniel.cloth:cloth-config-neoforge:${cloth_config_version}")
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
commonJava {
|
||||||
|
canBeResolved = false
|
||||||
|
canBeConsumed = true
|
||||||
|
}
|
||||||
|
commonResources {
|
||||||
|
canBeResolved = false
|
||||||
|
canBeConsumed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
artifacts {
|
||||||
|
commonJava sourceSets.main.java.sourceDirectories.singleFile
|
||||||
|
commonResources sourceSets.main.resources.sourceDirectories.singleFile
|
||||||
|
}
|
||||||
208
Common/src/main/java/tschipp/carryon/CarryOnCommon.java
Normal file
208
Common/src/main/java/tschipp/carryon/CarryOnCommon.java
Normal file
|
|
@ -0,0 +1,208 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
|
import net.minecraft.core.RegistryAccess;
|
||||||
|
import net.minecraft.core.RegistrySetBuilder;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData.CarryType;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnDataManager;
|
||||||
|
import tschipp.carryon.common.carry.PlacementHandler;
|
||||||
|
import tschipp.carryon.common.command.CommandCarryOn;
|
||||||
|
import tschipp.carryon.config.ConfigLoader;
|
||||||
|
import tschipp.carryon.networking.clientbound.ClientboundStartRidingOtherPlayerPacket;
|
||||||
|
import tschipp.carryon.networking.clientbound.ClientboundStartRidingPacket;
|
||||||
|
import tschipp.carryon.networking.clientbound.ClientboundSyncScriptsPacket;
|
||||||
|
import tschipp.carryon.networking.serverbound.ServerboundCarryKeyPressedPacket;
|
||||||
|
import tschipp.carryon.platform.Services;
|
||||||
|
|
||||||
|
public class CarryOnCommon
|
||||||
|
{
|
||||||
|
public static final RegistrySetBuilder BUILDER = new RegistrySetBuilder();
|
||||||
|
|
||||||
|
public static HolderLookup.Provider createLookup() {
|
||||||
|
RegistryAccess.Frozen registryaccess$frozen = RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY);
|
||||||
|
HolderLookup.Provider holderlookup$provider = BUILDER.build(registryaccess$frozen);
|
||||||
|
return holderlookup$provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerServerPackets(Object... args)
|
||||||
|
{
|
||||||
|
Services.PLATFORM.registerServerboundPacket(
|
||||||
|
ServerboundCarryKeyPressedPacket.TYPE,
|
||||||
|
ServerboundCarryKeyPressedPacket.class,
|
||||||
|
ServerboundCarryKeyPressedPacket.CODEC,
|
||||||
|
ServerboundCarryKeyPressedPacket::handle,
|
||||||
|
args
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerClientPackets(Object... args)
|
||||||
|
{
|
||||||
|
Services.PLATFORM.registerClientboundPacket(
|
||||||
|
ClientboundStartRidingPacket.TYPE,
|
||||||
|
ClientboundStartRidingPacket.class,
|
||||||
|
ClientboundStartRidingPacket.CODEC,
|
||||||
|
ClientboundStartRidingPacket::handle,
|
||||||
|
args
|
||||||
|
);
|
||||||
|
|
||||||
|
Services.PLATFORM.registerClientboundPacket(
|
||||||
|
ClientboundSyncScriptsPacket.TYPE,
|
||||||
|
ClientboundSyncScriptsPacket.class,
|
||||||
|
ClientboundSyncScriptsPacket.CODEC,
|
||||||
|
ClientboundSyncScriptsPacket::handle,
|
||||||
|
args
|
||||||
|
);
|
||||||
|
|
||||||
|
Services.PLATFORM.registerClientboundPacket(
|
||||||
|
ClientboundStartRidingOtherPlayerPacket.TYPE,
|
||||||
|
ClientboundStartRidingOtherPlayerPacket.class,
|
||||||
|
ClientboundStartRidingOtherPlayerPacket.CODEC,
|
||||||
|
ClientboundStartRidingOtherPlayerPacket::handle,
|
||||||
|
args
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerConfig()
|
||||||
|
{
|
||||||
|
ConfigLoader.registerConfig(Constants.COMMON_CONFIG);
|
||||||
|
ConfigLoader.registerConfig(Constants.CLIENT_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerCommands(CommandDispatcher<CommandSourceStack> dispatcher)
|
||||||
|
{
|
||||||
|
CommandCarryOn.register(dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void onCarryTick(ServerPlayer player)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if(carry.isCarrying())
|
||||||
|
{
|
||||||
|
// Dumb Fix to sync Carry Data after a respawn with KeepInventory, because we can't sync in the first tick.
|
||||||
|
if(player.tickCount == 1)
|
||||||
|
CarryOnDataManager.setCarryData(player, carry);
|
||||||
|
|
||||||
|
if(carry.getActiveScript().isPresent())
|
||||||
|
{
|
||||||
|
String cmd = carry.getActiveScript().get().scriptEffects().commandLoop();
|
||||||
|
if(!cmd.isEmpty())
|
||||||
|
player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Inventory inv = player.getInventory();
|
||||||
|
inv.setSelectedSlot(carry.getSelected());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the block can be broken.
|
||||||
|
*/
|
||||||
|
public static boolean onTryBreakBlock(Player player)
|
||||||
|
{
|
||||||
|
if (player != null && !Constants.COMMON_CONFIG.settings.hitWhileCarrying)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if(carry.isCarrying())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true of the entity can be attacked
|
||||||
|
*/
|
||||||
|
public static boolean onAttackedByPlayer(Player player)
|
||||||
|
{
|
||||||
|
if (player != null && !Constants.COMMON_CONFIG.settings.hitWhileCarrying)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if(carry.isCarrying())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onPlayerAttacked(Player player)
|
||||||
|
{
|
||||||
|
if (Constants.COMMON_CONFIG.settings.dropCarriedWhenHit && !player.level().isClientSide())
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if (carry.isCarrying())
|
||||||
|
{
|
||||||
|
PlacementHandler.placeCarried((ServerPlayer) player);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onRiderDisconnected(Player rider)
|
||||||
|
{
|
||||||
|
if(rider.getVehicle() instanceof ServerPlayer vehicle) {
|
||||||
|
CarryOnData data = CarryOnDataManager.getCarryData(vehicle);
|
||||||
|
if(data.isCarrying(CarryType.PLAYER)) {
|
||||||
|
PlacementHandler.placeCarried(vehicle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static int potionLevel(CarryOnData carry, Level level)
|
||||||
|
{
|
||||||
|
if(carry.isCarrying(CarryType.PLAYER))
|
||||||
|
return 1;
|
||||||
|
if(carry.isCarrying(CarryType.ENTITY))
|
||||||
|
{
|
||||||
|
Entity entity = carry.getEntity(level);
|
||||||
|
int i = (int) (entity.getBbHeight() * entity.getBbWidth());
|
||||||
|
if (i > 4)
|
||||||
|
i = 4;
|
||||||
|
if (!Constants.COMMON_CONFIG.settings.heavyEntities)
|
||||||
|
i = 1;
|
||||||
|
return (int) (i * Constants.COMMON_CONFIG.settings.entitySlownessMultiplier);
|
||||||
|
}
|
||||||
|
if(carry.isCarrying(CarryType.BLOCK))
|
||||||
|
{
|
||||||
|
String nbt = carry.getNbt().toString();
|
||||||
|
int i = nbt.length() / 500;
|
||||||
|
|
||||||
|
if (i > 4)
|
||||||
|
i = 4;
|
||||||
|
|
||||||
|
if (!Constants.COMMON_CONFIG.settings.heavyTiles)
|
||||||
|
i = 1;
|
||||||
|
|
||||||
|
return (int) (i * Constants.COMMON_CONFIG.settings.blockSlownessMultiplier);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import tschipp.carryon.client.keybinds.CarryOnKeybinds;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnDataManager;
|
||||||
|
|
||||||
|
public class CarryOnCommonClient
|
||||||
|
{
|
||||||
|
public static void checkForKeybinds()
|
||||||
|
{
|
||||||
|
Minecraft mc = Minecraft.getInstance();
|
||||||
|
Player player = mc.player;
|
||||||
|
if(player != null) {
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if ((CarryOnKeybinds.carryKey.isUnbound() ? player.isShiftKeyDown() : (CarryOnKeybinds.carryKey.isDown())) && !carry.isKeyPressed()) {
|
||||||
|
CarryOnKeybinds.onCarryKey(true);
|
||||||
|
carry.setKeyPressed(true);
|
||||||
|
CarryOnDataManager.setCarryData(player, carry);
|
||||||
|
} else if (!(CarryOnKeybinds.carryKey.isUnbound() ? player.isShiftKeyDown() : (CarryOnKeybinds.carryKey.isDown() ) ) && carry.isKeyPressed()) {
|
||||||
|
CarryOnKeybinds.onCarryKey(false);
|
||||||
|
carry.setKeyPressed(false);
|
||||||
|
CarryOnDataManager.setCarryData(player, carry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void onCarryClientTick() {
|
||||||
|
Player player = Minecraft.getInstance().player;
|
||||||
|
if (player != null) {
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if (carry.isCarrying()) {
|
||||||
|
int wantedSlot = carry.getSelected();
|
||||||
|
if (player.getInventory().getSelectedSlot() != wantedSlot) {
|
||||||
|
player.getInventory().setSelectedSlot(wantedSlot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Player getPlayer()
|
||||||
|
{
|
||||||
|
return Minecraft.getInstance().player;
|
||||||
|
}
|
||||||
|
}
|
||||||
43
Common/src/main/java/tschipp/carryon/Constants.java
Normal file
43
Common/src/main/java/tschipp/carryon/Constants.java
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon;
|
||||||
|
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import tschipp.carryon.common.config.CarryConfig;
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
|
||||||
|
public static final String MOD_ID = "carryon";
|
||||||
|
public static final String MOD_NAME = "Carry On";
|
||||||
|
public static final Logger LOG = LoggerFactory.getLogger(MOD_NAME);
|
||||||
|
|
||||||
|
public static final CarryConfig.Common COMMON_CONFIG = new CarryConfig.Common();
|
||||||
|
public static final CarryConfig.Client CLIENT_CONFIG = new CarryConfig.Client();
|
||||||
|
|
||||||
|
public static final Identifier PACKET_ID_KEY_PRESSED = Identifier.fromNamespaceAndPath(Constants.MOD_ID, "key_pressed");
|
||||||
|
public static final Identifier PACKET_ID_START_RIDING = Identifier.fromNamespaceAndPath(Constants.MOD_ID, "start_riding");
|
||||||
|
public static final Identifier PACKET_ID_SYNC_SCRIPTS = Identifier.fromNamespaceAndPath(Constants.MOD_ID, "sync_scripts");
|
||||||
|
public static final Identifier PACKET_ID_START_RIDING_OTHER = Identifier.fromNamespaceAndPath(Constants.MOD_ID, "start_riding_other");
|
||||||
|
public static final Identifier PACKET_ID_SYNC_CARRY_ON_DATA = Identifier.fromNamespaceAndPath(Constants.MOD_ID, "sync_carry_data");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.client.keybinds;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.InputConstants;
|
||||||
|
import net.minecraft.client.KeyMapping;
|
||||||
|
import net.minecraft.client.KeyMapping.Category;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.networking.serverbound.ServerboundCarryKeyPressedPacket;
|
||||||
|
import tschipp.carryon.platform.Services;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class CarryOnKeybinds
|
||||||
|
{
|
||||||
|
public static KeyMapping carryKey;
|
||||||
|
|
||||||
|
public static void registerKeybinds(Consumer<KeyMapping> registrar)
|
||||||
|
{
|
||||||
|
Category category = Category.register(Identifier.fromNamespaceAndPath(Constants.MOD_ID,"key.carry.category"));
|
||||||
|
|
||||||
|
carryKey = new KeyMapping("key.carry.desc", InputConstants.KEY_LSHIFT, category);
|
||||||
|
|
||||||
|
registrar.accept(carryKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onCarryKey(boolean pressed)
|
||||||
|
{
|
||||||
|
Services.PLATFORM.sendPacketToServer(Constants.PACKET_ID_KEY_PRESSED, new ServerboundCarryKeyPressedPacket(pressed));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.client.modeloverride;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.StringReader;
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import com.mojang.datafixers.util.Either;
|
||||||
|
import com.mojang.serialization.DataResult;
|
||||||
|
import net.minecraft.commands.arguments.blocks.BlockStateParser;
|
||||||
|
import net.minecraft.commands.arguments.blocks.BlockStateParser.BlockResult;
|
||||||
|
import net.minecraft.commands.arguments.item.ItemParser;
|
||||||
|
import net.minecraft.commands.arguments.item.ItemParser.ItemResult;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
|
import tschipp.carryon.common.scripting.Matchables.NBTCondition;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ModelOverride {
|
||||||
|
private BlockResult parsedBlock;
|
||||||
|
private Either<ItemStack, BlockState> renderObject;
|
||||||
|
|
||||||
|
private ModelOverride(String raw, BlockResult parsedBlock, Type type, Either<ItemResult, BlockResult> parsedRHS)
|
||||||
|
{
|
||||||
|
this.parsedBlock = parsedBlock;
|
||||||
|
|
||||||
|
parsedRHS.ifLeft(res -> {
|
||||||
|
ItemStack stack = new ItemStack(res.item());
|
||||||
|
if(res.components() != null)
|
||||||
|
stack.applyComponents(res.components());
|
||||||
|
this.renderObject = Either.left(stack);
|
||||||
|
});
|
||||||
|
|
||||||
|
parsedRHS.ifRight(res -> {
|
||||||
|
BlockState state = res.blockState();
|
||||||
|
this.renderObject = Either.right(state);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataResult<ModelOverride> of(String str, HolderLookup.Provider provider)
|
||||||
|
{
|
||||||
|
if(!str.contains("->"))
|
||||||
|
return DataResult.error(() -> str + " must contain -> Arrow!");
|
||||||
|
String[] split = str.split("->");
|
||||||
|
String from = split[0];
|
||||||
|
String to = split[1];
|
||||||
|
|
||||||
|
BlockResult res;
|
||||||
|
|
||||||
|
try {
|
||||||
|
res = BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK, from, true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return DataResult.error(() -> "Error while parsing " + from + ":" + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
Type type = Type.ITEM;
|
||||||
|
|
||||||
|
if(to.contains("(") && to.contains(")"))
|
||||||
|
{
|
||||||
|
String t = to.substring(to.indexOf("(") + 1, to.indexOf(")"));
|
||||||
|
if(t.equals("block"))
|
||||||
|
type = Type.BLOCK;
|
||||||
|
to = to.substring(to.indexOf(")") + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Either<ItemResult, BlockResult> either;
|
||||||
|
try {
|
||||||
|
if(type == Type.ITEM)
|
||||||
|
either = Either.left(new ItemParser(provider).parse(new StringReader(to)));
|
||||||
|
else
|
||||||
|
either = Either.right(BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK, to, true));
|
||||||
|
}catch (CommandSyntaxException e) {
|
||||||
|
String finalTo = to;
|
||||||
|
return DataResult.error(() -> "Error while parsing " + finalTo + ":" + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return DataResult.success(new ModelOverride(str, res, type, either));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(BlockState state, @Nullable CompoundTag tag)
|
||||||
|
{
|
||||||
|
if(state.getBlock() == parsedBlock.blockState().getBlock() && matchesProperties(state, parsedBlock.properties()))
|
||||||
|
{
|
||||||
|
if(tag == null || parsedBlock.nbt() == null)
|
||||||
|
return true;
|
||||||
|
NBTCondition nbt = new NBTCondition(parsedBlock.nbt());
|
||||||
|
return nbt.matches(tag);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Either<ItemStack, BlockState> getRenderObject()
|
||||||
|
{
|
||||||
|
return this.renderObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matchesProperties(BlockState state, Map<Property<?>, Comparable<?>> props)
|
||||||
|
{
|
||||||
|
for(var entry : props.entrySet())
|
||||||
|
{
|
||||||
|
var val = state.getValue(entry.getKey());
|
||||||
|
if(val != entry.getValue())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
ITEM,
|
||||||
|
BLOCK
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.client.modeloverride;
|
||||||
|
|
||||||
|
import com.mojang.serialization.DataResult;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class ModelOverrideHandler
|
||||||
|
{
|
||||||
|
private static List<ModelOverride> OVERRIDES = new ArrayList<>();
|
||||||
|
|
||||||
|
public static void initModelOverrides(HolderLookup.Provider provider)
|
||||||
|
{
|
||||||
|
OVERRIDES.clear();
|
||||||
|
|
||||||
|
for(String ov : Constants.CLIENT_CONFIG.modelOverrides)
|
||||||
|
{
|
||||||
|
addFromString(ov, provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<ModelOverride> getModelOverride(BlockState state, @Nullable CompoundTag tag)
|
||||||
|
{
|
||||||
|
for(ModelOverride ov : OVERRIDES)
|
||||||
|
{
|
||||||
|
if(ov.matches(state, tag))
|
||||||
|
return Optional.of(ov);
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addFromString(String str, HolderLookup.Provider provider)
|
||||||
|
{
|
||||||
|
DataResult<ModelOverride> res = ModelOverride.of(str, provider);
|
||||||
|
if(res.result().isPresent())
|
||||||
|
{
|
||||||
|
ModelOverride override = res.result().get();
|
||||||
|
OVERRIDES.add(override);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Constants.LOG.debug("Error while parsing ModelOverride: " + res.error().get().message());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.client.render;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
|
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
|
||||||
|
import net.minecraft.client.renderer.entity.state.EntityRenderState;
|
||||||
|
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||||
|
import net.minecraft.client.renderer.rendertype.RenderTypes;
|
||||||
|
import net.minecraft.client.renderer.state.CameraRenderState;
|
||||||
|
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.HumanoidArm;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData.CarryType;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnDataManager;
|
||||||
|
import tschipp.carryon.common.scripting.CarryOnScript.ScriptRender;
|
||||||
|
import tschipp.carryon.platform.Services;
|
||||||
|
|
||||||
|
public class CarriedObjectRender
|
||||||
|
{
|
||||||
|
public static boolean draw(Player player, PoseStack matrix, int light, float partialTicks,SubmitNodeCollector nodeCollector, boolean firstPerson)
|
||||||
|
{
|
||||||
|
if(Services.PLATFORM.isModLoaded("firstperson") || Services.PLATFORM.isModLoaded("firstpersonmod") || player == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
try {
|
||||||
|
if (carry.isCarrying(CarryType.BLOCK))
|
||||||
|
drawBlock(player, matrix, light, CarryRenderHelper.getRenderState(player), nodeCollector, firstPerson, partialTicks);
|
||||||
|
else if (carry.isCarrying(CarryType.ENTITY))
|
||||||
|
drawEntity(player, matrix, light, partialTicks, nodeCollector, firstPerson);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
//hehe
|
||||||
|
}
|
||||||
|
|
||||||
|
if(carry.getActiveScript().isPresent())
|
||||||
|
{
|
||||||
|
ScriptRender render = carry.getActiveScript().get().scriptRender();
|
||||||
|
if(!render.renderLeftArm() && player.getMainArm() == HumanoidArm.LEFT)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!render.renderRightArm() && player.getMainArm() == HumanoidArm.RIGHT)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return carry.isCarrying();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawBlock(Player player, PoseStack matrix, int light, BlockState state, SubmitNodeCollector nodeCollector, boolean firstPerson, float partialTicks)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
ItemStackRenderState renderState = new ItemStackRenderState();
|
||||||
|
var layer = renderState.newLayer();
|
||||||
|
layer.setRenderType(RenderTypes.glint());
|
||||||
|
|
||||||
|
matrix.pushPose();
|
||||||
|
|
||||||
|
PoseStack renderPose = CarryRenderHelper.setupBlockTransformations(player, matrix, carry, firstPerson);
|
||||||
|
|
||||||
|
ItemStack renderStack = CarryRenderHelper.getRenderItemStack(player);
|
||||||
|
Minecraft.getInstance().getItemModelResolver().updateForTopItem(renderState, renderStack, ItemDisplayContext.NONE, player.level(), null, 0);
|
||||||
|
renderState.submit(renderPose, nodeCollector, light, OverlayTexture.NO_OVERLAY, 0);
|
||||||
|
matrix.popPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawEntity(Player player, PoseStack matrix, int light, float partialTicks,SubmitNodeCollector nodeCollector, boolean firstPerson) {
|
||||||
|
EntityRenderDispatcher manager = Minecraft.getInstance().getEntityRenderDispatcher();
|
||||||
|
|
||||||
|
Entity entity = CarryRenderHelper.getRenderEntity(player);
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
|
||||||
|
if (entity == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Vec3 playerpos = CarryRenderHelper.getExactPos(player, partialTicks);
|
||||||
|
|
||||||
|
entity.setPos(playerpos.x, playerpos.y, playerpos.z);
|
||||||
|
entity.xRotO = 0.0f;
|
||||||
|
entity.yRotO = 0.0f;
|
||||||
|
entity.setYHeadRot(0.0f);
|
||||||
|
|
||||||
|
matrix.pushPose();
|
||||||
|
|
||||||
|
CarryRenderHelper.setupEntityTransformations(player, matrix, carry, firstPerson);
|
||||||
|
|
||||||
|
if (entity instanceof LivingEntity)
|
||||||
|
((LivingEntity) entity).hurtTime = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
EntityRenderState renderState = manager.extractEntity(entity, 0);
|
||||||
|
renderState.shadowPieces.clear();
|
||||||
|
renderState.lightCoords = light;
|
||||||
|
manager.submit(renderState, new CameraRenderState(), 0, 0, 0, matrix, nodeCollector);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix.popPose();
|
||||||
|
if(!firstPerson)
|
||||||
|
matrix.popPose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,446 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.client.render;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.math.Axis;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.util.ProblemReporter;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntitySpawnReason;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.Pose;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.ChestBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.TagValueInput;
|
||||||
|
import net.minecraft.world.level.storage.ValueInput;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.client.modeloverride.ModelOverride;
|
||||||
|
import tschipp.carryon.client.modeloverride.ModelOverrideHandler;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData.CarryType;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnDataManager;
|
||||||
|
import tschipp.carryon.common.scripting.CarryOnScript;
|
||||||
|
import tschipp.carryon.common.scripting.CarryOnScript.ScriptRender;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class CarryRenderHelper
|
||||||
|
{
|
||||||
|
public static Vec3 getExactPos(Entity entity, float partialticks)
|
||||||
|
{
|
||||||
|
return new Vec3(entity.xOld + (entity.getX() - entity.xOld) * partialticks, entity.yOld + (entity.getY() - entity.yOld) * partialticks, entity.zOld + (entity.getZ() - entity.zOld) * partialticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float getExactBodyRotationDegrees(LivingEntity entity, float partialticks)
|
||||||
|
{
|
||||||
|
if (entity.getVehicle() != null && entity.getVehicle() instanceof LivingEntity vehicle)
|
||||||
|
if(vehicle instanceof Player player)
|
||||||
|
return -(player.yBodyRotO + (player.yBodyRot - player.yBodyRotO) * partialticks);
|
||||||
|
else
|
||||||
|
return -(entity.yHeadRotO + (entity.yHeadRot - entity.yHeadRotO) * partialticks);
|
||||||
|
else
|
||||||
|
return -(entity.yBodyRotO + (entity.yBodyRot - entity.yBodyRotO) * partialticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternionf getExactBodyRotation(LivingEntity entity, float partialticks)
|
||||||
|
{
|
||||||
|
return Axis.YP.rotationDegrees(getExactBodyRotationDegrees(entity, partialticks));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void applyGeneralTransformations(Player player, PoseStack matrix)
|
||||||
|
{
|
||||||
|
Pose pose = player.getPose();
|
||||||
|
|
||||||
|
matrix.pushPose();
|
||||||
|
matrix.scale(0.6f, 0.6f, 0.6f);
|
||||||
|
|
||||||
|
matrix.translate(0, 0, -1.35);
|
||||||
|
|
||||||
|
if (doSneakCheck(player))
|
||||||
|
{
|
||||||
|
matrix.translate(0, -0.4, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pose == Pose.SWIMMING || pose == Pose.FALL_FLYING)
|
||||||
|
{
|
||||||
|
matrix.translate(0, 0, 2.5);
|
||||||
|
matrix.mulPose(Axis.XP.rotationDegrees(90));
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix.translate(0, -0.5, 0.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PoseStack setupBlockTransformations(Player player, PoseStack matrix, CarryOnData carry, boolean firstPerson) {
|
||||||
|
if (firstPerson) {
|
||||||
|
matrix.scale(2.5f, 2.5f, 2.5f);
|
||||||
|
matrix.translate(0, -0.5, -1);
|
||||||
|
|
||||||
|
if (Constants.CLIENT_CONFIG.facePlayer != CarryRenderHelper.isChest(carry.getBlock().getBlock())) {
|
||||||
|
matrix.mulPose(Axis.YP.rotationDegrees(180));
|
||||||
|
matrix.mulPose(Axis.XN.rotationDegrees(8));
|
||||||
|
} else {
|
||||||
|
matrix.mulPose(Axis.XP.rotationDegrees(8));
|
||||||
|
}
|
||||||
|
carry.getActiveScript().ifPresent(script -> CarryRenderHelper.performScriptTransformation(matrix, script));
|
||||||
|
|
||||||
|
return matrix;
|
||||||
|
} else {
|
||||||
|
CarryRenderHelper.applyBlockTransformations(player, matrix, carry.getBlock().getBlock());
|
||||||
|
carry.getActiveScript().ifPresent(script -> CarryRenderHelper.performScriptTransformation(matrix, script));
|
||||||
|
|
||||||
|
PoseStack.Pose p = matrix.last();
|
||||||
|
PoseStack copy = new PoseStack();
|
||||||
|
copy.mulPose(p.pose());
|
||||||
|
matrix.popPose();
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void applyBlockTransformations(Player player, PoseStack matrix, Block block)
|
||||||
|
{
|
||||||
|
matrix.mulPose(Axis.ZN.rotationDegrees(180));
|
||||||
|
applyGeneralTransformations(player, matrix);
|
||||||
|
|
||||||
|
if (Constants.CLIENT_CONFIG.facePlayer != CarryRenderHelper.isChest(block))
|
||||||
|
{
|
||||||
|
//TODO: RealFirstPersonRender
|
||||||
|
//if ((ModList.get().isLoaded("realrender") || ModList.get().isLoaded("rfpr")) && perspective == 0)
|
||||||
|
// matrix.translate(0, 0, -0.4);
|
||||||
|
matrix.mulPose(Axis.YP.rotationDegrees(180));
|
||||||
|
}
|
||||||
|
|
||||||
|
float height = getRenderHeight(player);
|
||||||
|
float offset = (height - 1f) / 1.2f;
|
||||||
|
matrix.translate(0, -offset, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setupEntityTransformations(Player player, PoseStack matrix, CarryOnData carry, boolean firstPerson) {
|
||||||
|
|
||||||
|
Entity entity = carry.getEntity(player.level());
|
||||||
|
|
||||||
|
float height = entity.getBbHeight();
|
||||||
|
float width = entity.getBbWidth();
|
||||||
|
|
||||||
|
if(firstPerson) {
|
||||||
|
matrix.mulPose(Axis.YP.rotationDegrees(180));
|
||||||
|
|
||||||
|
matrix.scale(0.8f, 0.8f, 0.8f);
|
||||||
|
matrix.translate(0.0, -height - .2, width * 1.3 + 0.1);
|
||||||
|
|
||||||
|
carry.getActiveScript().ifPresent(script -> CarryRenderHelper.performScriptTransformation(matrix, script));
|
||||||
|
|
||||||
|
if(Constants.CLIENT_CONFIG.rotateEntitiesSideways)
|
||||||
|
matrix.mulPose(Axis.YP.rotationDegrees(90));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
applyEntityTransformations(player, matrix, entity);
|
||||||
|
|
||||||
|
carry.getActiveScript().ifPresent(script -> CarryRenderHelper.performScriptTransformation(matrix, script));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void applyEntityTransformations(Player player, PoseStack matrix, Entity entity)
|
||||||
|
{
|
||||||
|
Pose pose = player.getPose();
|
||||||
|
|
||||||
|
applyGeneralTransformations(player, matrix);
|
||||||
|
|
||||||
|
matrix.mulPose(Axis.XP.rotationDegrees(180));
|
||||||
|
|
||||||
|
matrix.translate(0, -3.1, -0.65);
|
||||||
|
matrix.scale(1.666f, 1.666f, 1.666f);
|
||||||
|
|
||||||
|
float height = entity.getBbHeight();
|
||||||
|
float width = entity.getBbWidth();
|
||||||
|
float multiplier = Math.min(9.9f, height * width) ;
|
||||||
|
entity.yo = 0.0f;
|
||||||
|
entity.yRotO = 0.0f;
|
||||||
|
entity.setYHeadRot(0.0f);
|
||||||
|
entity.xo = 0.0f;
|
||||||
|
entity.xRotO = 0.0f;
|
||||||
|
|
||||||
|
matrix.scale((10 - multiplier) * 0.08f, (10 - multiplier) * 0.08f, (10 - multiplier) * 0.08f);
|
||||||
|
matrix.translate(0.0, height / 2 + -(height / 4) + 1, width - 0.1 < 0.7 ? width - 0.1 + (0.7 - (width - 0.1)) : width - 0.1);
|
||||||
|
|
||||||
|
if(doSneakCheck(player))
|
||||||
|
matrix.translate(0, -0.4, 0);
|
||||||
|
|
||||||
|
if (pose == Pose.SWIMMING || pose == Pose.FALL_FLYING)
|
||||||
|
{
|
||||||
|
matrix.mulPose(Axis.XN.rotationDegrees(180));
|
||||||
|
matrix.translate(0, 0.2 * height - 2, -0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Constants.CLIENT_CONFIG.rotateEntitiesSideways)
|
||||||
|
matrix.mulPose(Axis.YP.rotationDegrees(90));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void performScriptTransformation(PoseStack matrix, CarryOnScript script)
|
||||||
|
{
|
||||||
|
int perspective = getPerspective();
|
||||||
|
|
||||||
|
ScriptRender render = script.scriptRender();
|
||||||
|
|
||||||
|
Vec3 translation = render.renderTranslation().getVec();
|
||||||
|
Vec3 rotation = render.renderRotation().getVec();
|
||||||
|
Vec3 scale = render.renderscale().getVec(1, 1, 1);
|
||||||
|
|
||||||
|
Quaternionf rot = Axis.XP.rotationDegrees((float) rotation.x);
|
||||||
|
rot.mul(Axis.YP.rotationDegrees((float) rotation.y));
|
||||||
|
rot.mul(Axis.ZP.rotationDegrees((float) rotation.z));
|
||||||
|
matrix.mulPose(rot);
|
||||||
|
|
||||||
|
matrix.translate(translation.x, translation.y, perspective == 1 && script.isBlock() ? -translation.z : translation.z);
|
||||||
|
|
||||||
|
matrix.scale((float) scale.x, (float) scale.y, (float) scale.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@Deprecated
|
||||||
|
public static void renderBakedModel(ItemStack stack, PoseStack matrix, MultiBufferSource buffer, int light, BakedModel model)
|
||||||
|
{
|
||||||
|
ItemStackRenderState state = new ItemStackRenderState();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
|
||||||
|
ItemStackRenderState.LayerRenderState layer = state.newLayer();
|
||||||
|
if(stack.hasFoil())
|
||||||
|
layer.setFoilType(ItemStackRenderState.FoilType.STANDARD);
|
||||||
|
layer.setupBlockModel(model, RenderType.translucent());
|
||||||
|
|
||||||
|
state.render(matrix, buffer, light, OverlayTexture.NO_OVERLAY);
|
||||||
|
|
||||||
|
|
||||||
|
ItemRenderer renderer = Minecraft.getInstance().getItemRenderer();
|
||||||
|
renderer.renderStatic(stack, ItemDisplayContext.NONE, light, OverlayTexture.NO_OVERLAY, matrix, buffer, null, model, 0);
|
||||||
|
renderer.render(stack, ItemDisplayContext.NONE, false, matrix, buffer, light, OverlayTexture.NO_OVERLAY, model);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static ItemStack getRenderItemStack(Player player)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
BlockState state = carry.getBlock().getBlock().defaultBlockState();
|
||||||
|
if(carry.getActiveScript().isPresent())
|
||||||
|
{
|
||||||
|
ScriptRender render = carry.getActiveScript().get().scriptRender();
|
||||||
|
if(render.renderNameBlock().isPresent())
|
||||||
|
{
|
||||||
|
state = BuiltInRegistries.BLOCK.get(render.renderNameBlock().get()).get().value().defaultBlockState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack renderStack = ItemStack.EMPTY;
|
||||||
|
|
||||||
|
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt());
|
||||||
|
if(ov.isPresent())
|
||||||
|
{
|
||||||
|
var renderObj = ov.get().getRenderObject();
|
||||||
|
if(renderObj.right().isPresent())
|
||||||
|
state = renderObj.right().get();
|
||||||
|
else if (renderObj.left().isPresent())
|
||||||
|
renderStack = renderObj.left().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(renderStack.isEmpty())
|
||||||
|
renderStack = new ItemStack(state.getBlock());
|
||||||
|
|
||||||
|
return renderStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockState getRenderState(Player player)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
BlockState state = carry.getBlock().getBlock().defaultBlockState();
|
||||||
|
if(carry.getActiveScript().isPresent())
|
||||||
|
{
|
||||||
|
ScriptRender render = carry.getActiveScript().get().scriptRender();
|
||||||
|
if(render.renderNameBlock().isPresent())
|
||||||
|
{
|
||||||
|
state = BuiltInRegistries.BLOCK.get(render.renderNameBlock().get()).get().value().defaultBlockState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt());
|
||||||
|
if(ov.isPresent())
|
||||||
|
{
|
||||||
|
var renderObj = ov.get().getRenderObject();
|
||||||
|
if(renderObj.right().isPresent())
|
||||||
|
state = renderObj.right().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
@Deprecated
|
||||||
|
public static BakedModel getRenderBlock(Player player)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
ItemRenderer renderer = Minecraft.getInstance().getItemRenderer();
|
||||||
|
Minecraft.getInstance().getModelManager().specialBlockModelRenderer().get().
|
||||||
|
BlockState state = getRenderState(player);
|
||||||
|
BakedModel model = Minecraft.getInstance().getBlockRenderer().getBlockModel(state);
|
||||||
|
|
||||||
|
if(state.getRenderShape() != RenderShape.MODEL || model.isCustomRenderer() || model.getQuads(state, null, RandomSource.create()).size() <= 0) {
|
||||||
|
ItemStack stack = new ItemStack(state.getBlock());
|
||||||
|
model = renderer.getModel(stack, player.level(), player, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt());
|
||||||
|
if(ov.isPresent())
|
||||||
|
{
|
||||||
|
var renderObj = ov.get().getRenderObject();
|
||||||
|
if(renderObj.left().isPresent())
|
||||||
|
model = renderer.getModel(renderObj.left().get(), player.level(), player, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static Entity getRenderEntity(Player player)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
Entity entity = carry.getEntity(player.level());
|
||||||
|
|
||||||
|
if(carry.getActiveScript().isPresent())
|
||||||
|
{
|
||||||
|
CarryOnScript script = carry.getActiveScript().get();
|
||||||
|
ScriptRender render = script.scriptRender();
|
||||||
|
if(render.renderNameEntity().isPresent())
|
||||||
|
entity = BuiltInRegistries.ENTITY_TYPE.get(render.renderNameEntity().get()).get().value().create(player.level(), EntitySpawnReason.EVENT);
|
||||||
|
|
||||||
|
if(render.renderNBT().isPresent()) {
|
||||||
|
ValueInput input = TagValueInput.create(new ProblemReporter.ScopedCollector(Constants.LOG), player.registryAccess(), render.renderNBT().get());
|
||||||
|
entity.load(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float getRenderWidth(Player player)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if(carry.isCarrying(CarryType.BLOCK))
|
||||||
|
{
|
||||||
|
BlockState state = getRenderState(player);
|
||||||
|
VoxelShape shape = state.getShape(player.level(), player.blockPosition());
|
||||||
|
if(shape == null || shape.isEmpty())
|
||||||
|
return 1f;
|
||||||
|
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt());
|
||||||
|
if(ov.isPresent())
|
||||||
|
{
|
||||||
|
var renderObj = ov.get().getRenderObject();
|
||||||
|
if(renderObj.left().isPresent())
|
||||||
|
return 0.8f;
|
||||||
|
}
|
||||||
|
float width = (float)Math.abs(shape.bounds().maxX - shape.bounds().minX);
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
else if(carry.isCarrying(CarryType.ENTITY))
|
||||||
|
{
|
||||||
|
Entity entity = getRenderEntity(player);
|
||||||
|
float w = entity.getBbWidth();
|
||||||
|
if (Constants.CLIENT_CONFIG.rotateEntitiesSideways)
|
||||||
|
return w - (w*w) * 0.35f;
|
||||||
|
return w * 0.9f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float getRenderHeight(Player player)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if(carry.isCarrying(CarryType.BLOCK))
|
||||||
|
{
|
||||||
|
BlockState state = getRenderState(player);
|
||||||
|
VoxelShape shape = state.getShape(player.level(), player.blockPosition());
|
||||||
|
if(shape == null || shape.isEmpty())
|
||||||
|
return 1f;
|
||||||
|
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(state, carry.getContentNbt());
|
||||||
|
if(ov.isPresent())
|
||||||
|
{
|
||||||
|
var renderObj = ov.get().getRenderObject();
|
||||||
|
if(renderObj.left().isPresent())
|
||||||
|
return 0.5f;
|
||||||
|
}
|
||||||
|
float height = (float)Math.abs(shape.bounds().maxY - shape.bounds().minY);
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
else if(carry.isCarrying(CarryType.ENTITY))
|
||||||
|
{
|
||||||
|
Entity entity = getRenderEntity(player);
|
||||||
|
return entity.getBbHeight();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("resource")
|
||||||
|
public static int getPerspective()
|
||||||
|
{
|
||||||
|
boolean isThirdPerson = !Minecraft.getInstance().options.getCameraType().isFirstPerson(); // isThirdPerson
|
||||||
|
boolean isThirdPersonReverse = Minecraft.getInstance().options.getCameraType().isMirrored();
|
||||||
|
|
||||||
|
if (!isThirdPerson && !isThirdPersonReverse)
|
||||||
|
return 0;
|
||||||
|
if (isThirdPerson && !isThirdPersonReverse)
|
||||||
|
return 1;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean doSneakCheck(Player player)
|
||||||
|
{
|
||||||
|
if (player.getAbilities().flying)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return player.isShiftKeyDown() || player.isCrouching();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isChest(Block block)
|
||||||
|
{
|
||||||
|
return block == Blocks.CHEST || block == Blocks.ENDER_CHEST || block == Blocks.TRAPPED_CHEST || block instanceof ChestBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,279 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.common.carry;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.DataResult;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.NbtOps;
|
||||||
|
import net.minecraft.nbt.NbtUtils;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||||
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.util.ProblemReporter;
|
||||||
|
import net.minecraft.world.entity.AreaEffectCloud;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntitySpawnReason;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||||
|
import net.minecraft.world.level.storage.TagValueInput;
|
||||||
|
import net.minecraft.world.level.storage.TagValueOutput;
|
||||||
|
import net.minecraft.world.level.storage.ValueInput;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.common.scripting.CarryOnScript;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class CarryOnData {
|
||||||
|
|
||||||
|
private CarryType type;
|
||||||
|
private CompoundTag nbt;
|
||||||
|
private boolean keyPressed = false;
|
||||||
|
private CarryOnScript activeScript;
|
||||||
|
private int selectedSlot = 0;
|
||||||
|
private static final ProblemReporter problemReporter = new ProblemReporter.ScopedCollector(Constants.LOG);
|
||||||
|
|
||||||
|
|
||||||
|
public static final Codec<CarryOnData> CODEC = CompoundTag.CODEC.flatXmap(
|
||||||
|
tag -> {
|
||||||
|
try {
|
||||||
|
return DataResult.success(new CarryOnData(tag));
|
||||||
|
} catch (Exception e) {
|
||||||
|
return DataResult.error(e::getMessage);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
carry -> {
|
||||||
|
try {
|
||||||
|
return DataResult.success(carry.getNbt());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return DataResult.error(e::getMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final StreamCodec<RegistryFriendlyByteBuf, CarryOnData> STREAM_CODEC = ByteBufCodecs.fromCodecWithRegistries(CODEC);
|
||||||
|
|
||||||
|
public static final String SERIALIZATION_KEY = "CarryOnData";
|
||||||
|
|
||||||
|
public CarryOnData(CompoundTag data)
|
||||||
|
{
|
||||||
|
if(data.contains("type"))
|
||||||
|
this.type = CarryType.valueOf(data.getStringOr("type", "INVALID"));
|
||||||
|
else
|
||||||
|
this.type = CarryType.INVALID;
|
||||||
|
|
||||||
|
this.nbt = data;
|
||||||
|
|
||||||
|
this.keyPressed = data.getBooleanOr("keyPressed", false);
|
||||||
|
|
||||||
|
if(data.contains("activeScript"))
|
||||||
|
{
|
||||||
|
DataResult<CarryOnScript> res = CarryOnScript.CODEC.parse(NbtOps.INSTANCE, data.get("activeScript"));
|
||||||
|
this.activeScript = res.getOrThrow((s) -> {throw new RuntimeException("Failed to decode activeScript during CarryOnData serialization: " + s);});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectedSlot = data.getIntOr("selected", 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public CarryType getType()
|
||||||
|
{
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundTag getNbt()
|
||||||
|
{
|
||||||
|
nbt.putString("type", type.toString());
|
||||||
|
nbt.putBoolean("keyPressed", keyPressed);
|
||||||
|
if(activeScript != null)
|
||||||
|
{
|
||||||
|
DataResult<Tag> res = CarryOnScript.CODEC.encodeStart(NbtOps.INSTANCE, activeScript);
|
||||||
|
Tag tag = res.getOrThrow((s) -> {throw new RuntimeException("Failed to encode activeScript during CarryOnData serialization: " + s);});
|
||||||
|
nbt.put("activeScript", tag);
|
||||||
|
}
|
||||||
|
nbt.putInt("selected", this.selectedSlot);
|
||||||
|
return nbt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundTag getContentNbt()
|
||||||
|
{
|
||||||
|
if(type == CarryType.BLOCK && nbt.contains("block"))
|
||||||
|
return nbt.getCompoundOrEmpty("block");
|
||||||
|
else if(type == CarryType.ENTITY && nbt.contains("entity"))
|
||||||
|
return nbt.getCompoundOrEmpty("entity");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlock(BlockState state, @Nullable BlockEntity tile, ServerPlayer player, BlockPos pos)
|
||||||
|
{
|
||||||
|
this.type = CarryType.BLOCK;
|
||||||
|
|
||||||
|
if(state.hasProperty(BlockStateProperties.WATERLOGGED))
|
||||||
|
state = state.setValue(BlockStateProperties.WATERLOGGED, false);
|
||||||
|
|
||||||
|
CompoundTag stateData = NbtUtils.writeBlockState(state);
|
||||||
|
nbt.put("block", stateData);
|
||||||
|
|
||||||
|
if(tile != null)
|
||||||
|
{
|
||||||
|
TagValueOutput output = TagValueOutput.createWithContext(problemReporter, player.registryAccess());
|
||||||
|
tile.saveWithId(output);
|
||||||
|
Tag tileData = output.buildResult();
|
||||||
|
nbt.put("tile", tileData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockState getBlock()
|
||||||
|
{
|
||||||
|
if(this.type != CarryType.BLOCK)
|
||||||
|
throw new IllegalStateException("Called getBlock on data that contained " + this.type);
|
||||||
|
|
||||||
|
return NbtUtils.readBlockState(BuiltInRegistries.BLOCK, nbt.getCompoundOrEmpty("block"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public BlockEntity getBlockEntity(BlockPos pos, HolderLookup.Provider lookup)
|
||||||
|
{
|
||||||
|
if(this.type != CarryType.BLOCK)
|
||||||
|
throw new IllegalStateException("Called getBlockEntity on data that contained " + this.type);
|
||||||
|
|
||||||
|
if(!nbt.contains("tile"))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return BlockEntity.loadStatic(pos, this.getBlock(), nbt.getCompoundOrEmpty("tile"), lookup);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEntity(Entity entity)
|
||||||
|
{
|
||||||
|
this.type = CarryType.ENTITY;
|
||||||
|
TagValueOutput output = TagValueOutput.createWithContext(new ProblemReporter.ScopedCollector(Constants.LOG), entity.registryAccess());
|
||||||
|
entity.save(output);
|
||||||
|
Tag entityData = output.buildResult();
|
||||||
|
nbt.put("entity", entityData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Entity getEntity(Level level)
|
||||||
|
{
|
||||||
|
if(this.type != CarryType.ENTITY)
|
||||||
|
throw new IllegalStateException("Called getEntity on data that contained " + this.type);
|
||||||
|
|
||||||
|
ValueInput in = TagValueInput.create(problemReporter, level.registryAccess(), nbt.getCompoundOrEmpty("entity"));
|
||||||
|
var optionalEntity = EntityType.create(in, level, EntitySpawnReason.BUCKET);
|
||||||
|
if(optionalEntity.isPresent())
|
||||||
|
return optionalEntity.get();
|
||||||
|
|
||||||
|
Constants.LOG.error("Called EntityType#create even though no entity data was present. Data: " + nbt.toString());
|
||||||
|
this.clear();
|
||||||
|
return new AreaEffectCloud(level, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<CarryOnScript> getActiveScript()
|
||||||
|
{
|
||||||
|
if(activeScript == null)
|
||||||
|
return Optional.empty();
|
||||||
|
return Optional.of(activeScript);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActiveScript(CarryOnScript script)
|
||||||
|
{
|
||||||
|
this.activeScript = script;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCarryingPlayer(Player player)
|
||||||
|
{
|
||||||
|
this.type = CarryType.PLAYER;
|
||||||
|
nbt.putString("player", player.getStringUUID().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getCarryingPlayer(Level level)
|
||||||
|
{
|
||||||
|
if(this.type != CarryType.PLAYER)
|
||||||
|
throw new IllegalStateException("Called getCarryingPlayer on data that contained " + this.type);
|
||||||
|
if(!nbt.contains("player"))
|
||||||
|
return null;
|
||||||
|
UUID uuid = UUID.fromString(nbt.getString("player").get());
|
||||||
|
return level.getServer().getPlayerList().getPlayer(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCarrying()
|
||||||
|
{
|
||||||
|
return this.type != CarryType.INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCarrying(CarryType type)
|
||||||
|
{
|
||||||
|
return this.type == type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isKeyPressed() {return this.keyPressed;}
|
||||||
|
|
||||||
|
public void setKeyPressed(boolean val) {
|
||||||
|
this.keyPressed = val;
|
||||||
|
this.nbt.putBoolean("keyPressed", val);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelected(int selectedSlot) {
|
||||||
|
this.selectedSlot = selectedSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSelected() {
|
||||||
|
return this.selectedSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
this.type = CarryType.INVALID;
|
||||||
|
this.nbt = new CompoundTag();
|
||||||
|
this.activeScript = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CarryOnData clone() {
|
||||||
|
return new CarryOnData(nbt.copy());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTick()
|
||||||
|
{
|
||||||
|
return this.nbt.getIntOr("tick", -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTick(int tick) {
|
||||||
|
this.nbt.putInt("tick", tick);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public enum CarryType {
|
||||||
|
BLOCK,
|
||||||
|
ENTITY,
|
||||||
|
PLAYER,
|
||||||
|
INVALID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.common.carry;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import tschipp.carryon.platform.Services;
|
||||||
|
|
||||||
|
public class CarryOnDataManager {
|
||||||
|
|
||||||
|
public static CarryOnData getCarryData(Player player)
|
||||||
|
{
|
||||||
|
return Services.PLATFORM.getCarryData(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setCarryData(Player player, CarryOnData data)
|
||||||
|
{
|
||||||
|
data.setSelected(player.getInventory().getSelectedSlot());
|
||||||
|
data.setTick(player.tickCount);
|
||||||
|
Services.PLATFORM.setCarryData(player, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,291 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.common.carry;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import net.minecraft.sounds.SoundSource;
|
||||||
|
import net.minecraft.util.ProblemReporter;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
|
import net.minecraft.world.effect.MobEffects;
|
||||||
|
import net.minecraft.world.entity.*;
|
||||||
|
import net.minecraft.world.entity.Entity.RemovalReason;
|
||||||
|
import net.minecraft.world.entity.animal.Animal;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.GameType;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.DoorBlock;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
|
import net.minecraft.world.level.storage.TagValueOutput;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import tschipp.carryon.CarryOnCommon;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.common.config.ListHandler;
|
||||||
|
import tschipp.carryon.common.pickupcondition.PickupCondition;
|
||||||
|
import tschipp.carryon.common.pickupcondition.PickupConditionHandler;
|
||||||
|
import tschipp.carryon.common.scripting.CarryOnScript;
|
||||||
|
import tschipp.carryon.common.scripting.ScriptManager;
|
||||||
|
import tschipp.carryon.networking.clientbound.ClientboundStartRidingOtherPlayerPacket;
|
||||||
|
import tschipp.carryon.platform.Services;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class PickupHandler {
|
||||||
|
|
||||||
|
public static boolean canCarryGeneral(ServerPlayer player, Vec3 pos)
|
||||||
|
{
|
||||||
|
if(!player.getMainHandItem().isEmpty() || !player.getOffhandItem().isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(player.position().distanceTo(pos) > Constants.COMMON_CONFIG.settings.maxDistance)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if(carry.isCarrying())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!carry.isKeyPressed())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//Needed so that we don't pick up and place in the same tick
|
||||||
|
if(player.tickCount == carry.getTick())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (player.gameMode.getGameModeForPlayer() == GameType.SPECTATOR || player.gameMode.getGameModeForPlayer() == GameType.ADVENTURE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean tryPickUpBlock(ServerPlayer player, BlockPos pos, Level level, @Nullable BiFunction<BlockState, BlockPos, Boolean> pickupCallback)
|
||||||
|
{
|
||||||
|
if(!canCarryGeneral(player, Vec3.atCenterOf(pos)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
BlockEntity blockEntity = level.getBlockEntity(pos);
|
||||||
|
BlockState state = level.getBlockState(pos);
|
||||||
|
CompoundTag nbt = null;
|
||||||
|
if(blockEntity != null) {
|
||||||
|
TagValueOutput output = TagValueOutput.createWithContext(new ProblemReporter.ScopedCollector(Constants.LOG), level.registryAccess());
|
||||||
|
blockEntity.saveWithId(output);
|
||||||
|
nbt = output.buildResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<CarryOnScript> result = ScriptManager.inspectBlock(state, level, pos, nbt);
|
||||||
|
boolean overrideChecks = result.map(CarryOnScript::overrideChecks).orElse(false);
|
||||||
|
|
||||||
|
if(!ListHandler.isPermitted(state.getBlock()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Reject pickup of Double blocks, if they use the vanilla property
|
||||||
|
if(hasPropertyType(state, DoorBlock.HALF))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!overrideChecks && (state.getDestroySpeed(level, pos) == -1 && !player.isCreative() && !Constants.COMMON_CONFIG.settings.pickupUnbreakableBlocks))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!overrideChecks && (blockEntity == null && !Constants.COMMON_CONFIG.settings.pickupAllBlocks))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//Check if TE is locked
|
||||||
|
if(blockEntity != null)
|
||||||
|
{
|
||||||
|
if(nbt.contains("Lock") && !nbt.getString("Lock").equals(""))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<PickupCondition> cond = PickupConditionHandler.getPickupCondition(state);
|
||||||
|
if(cond.isPresent())
|
||||||
|
{
|
||||||
|
if(!cond.get().isFulfilled(player))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean doPickup = pickupCallback == null ? true : pickupCallback.apply(state, pos);
|
||||||
|
if(!doPickup)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(result.isPresent())
|
||||||
|
{
|
||||||
|
CarryOnScript script = result.get();
|
||||||
|
if(!script.fulfillsConditions(player))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
carry.setActiveScript(script);
|
||||||
|
|
||||||
|
String cmd = script.scriptEffects().commandInit();
|
||||||
|
if(!cmd.isEmpty())
|
||||||
|
player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
carry.setBlock(state, blockEntity, player, pos);
|
||||||
|
|
||||||
|
level.removeBlockEntity(pos);
|
||||||
|
level.removeBlock(pos, false);
|
||||||
|
|
||||||
|
CarryOnDataManager.setCarryData(player, carry);
|
||||||
|
level.playSound(null, pos, state.getSoundType().getHitSound(), SoundSource.BLOCKS, 1.0f, 0.5f);
|
||||||
|
player.swing(InteractionHand.MAIN_HAND, true);
|
||||||
|
if (!player.isCreative() || Constants.COMMON_CONFIG.settings.slownessInCreative)
|
||||||
|
player.addEffect(new MobEffectInstance(MobEffects.SLOWNESS, 100000000, CarryOnCommon.potionLevel(carry, player.level()), false, false));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean tryPickupEntity(ServerPlayer player, Entity entity, @Nullable Function<Entity, Boolean> pickupCallback)
|
||||||
|
{
|
||||||
|
if(!canCarryGeneral(player, entity.position()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (entity.invulnerableTime != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(entity.isRemoved())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (entity instanceof TamableAnimal tame)
|
||||||
|
{
|
||||||
|
EntityReference<LivingEntity> ref = tame.getOwnerReference();
|
||||||
|
if (ref != null) {
|
||||||
|
UUID owner = ref.getUUID();
|
||||||
|
UUID playerID = player.getGameProfile().id();
|
||||||
|
if (!owner.equals(playerID))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<CarryOnScript> result = ScriptManager.inspectEntity(entity);
|
||||||
|
boolean overrideChecks = result.map(CarryOnScript::overrideChecks).orElse(false);
|
||||||
|
|
||||||
|
if(!ListHandler.isPermitted(entity))
|
||||||
|
{
|
||||||
|
//We can pick up baby animals even if the grown up animal is blacklisted.
|
||||||
|
if(!overrideChecks && (!(entity instanceof AgeableMob ageableMob && Constants.COMMON_CONFIG.settings.allowBabies && (ageableMob.getAge() < 0 || ageableMob.isBaby()))))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Non-Creative only guards
|
||||||
|
if(!player.isCreative())
|
||||||
|
{
|
||||||
|
if(!overrideChecks && (!Constants.COMMON_CONFIG.settings.pickupHostileMobs && entity.getType().getCategory() == MobCategory.MONSTER))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(Constants.COMMON_CONFIG.settings.maxEntityHeight < entity.getBbHeight() || Constants.COMMON_CONFIG.settings.maxEntityWidth < entity.getBbWidth())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<PickupCondition> cond = PickupConditionHandler.getPickupCondition(entity);
|
||||||
|
if(cond.isPresent())
|
||||||
|
{
|
||||||
|
if(!cond.get().isFulfilled(player))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean doPickup = pickupCallback == null || pickupCallback.apply(entity);
|
||||||
|
if(!doPickup)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
|
||||||
|
if(result.isPresent())
|
||||||
|
{
|
||||||
|
CarryOnScript script = result.get();
|
||||||
|
if(!script.fulfillsConditions(player))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
carry.setActiveScript(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity instanceof Player otherPlayer) {
|
||||||
|
if (!Constants.COMMON_CONFIG.settings.pickupPlayers)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!player.isCreative() && otherPlayer.isCreative())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
otherPlayer.ejectPassengers();
|
||||||
|
otherPlayer.stopRiding();
|
||||||
|
|
||||||
|
if (result.isPresent()) {
|
||||||
|
String cmd = result.get().scriptEffects().commandInit();
|
||||||
|
if (!cmd.isEmpty())
|
||||||
|
player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
otherPlayer.startRiding(player, true, false);
|
||||||
|
Services.PLATFORM.sendPacketToAllPlayers(Constants.PACKET_ID_START_RIDING_OTHER, new ClientboundStartRidingOtherPlayerPacket(player.getId(), otherPlayer.getId(), true), player.level());
|
||||||
|
carry.setCarryingPlayer(otherPlayer);
|
||||||
|
player.swing(InteractionHand.MAIN_HAND, true);
|
||||||
|
player.level().playSound(null, player.getOnPos(), SoundEvents.ARMOR_EQUIP_GENERIC.value(), SoundSource.AMBIENT, 1.0f, 0.5f);
|
||||||
|
CarryOnDataManager.setCarryData(player, carry);
|
||||||
|
if (!player.isCreative() || Constants.COMMON_CONFIG.settings.slownessInCreative)
|
||||||
|
player.addEffect(new MobEffectInstance(MobEffects.SLOWNESS, 100000000, CarryOnCommon.potionLevel(carry, player.level()), false, false));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.ejectPassengers();
|
||||||
|
entity.stopRiding();
|
||||||
|
if (entity instanceof Animal animal) {
|
||||||
|
animal.dropLeash();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result.isPresent())
|
||||||
|
{
|
||||||
|
String cmd = result.get().scriptEffects().commandInit();
|
||||||
|
if(!cmd.isEmpty())
|
||||||
|
player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
carry.setEntity(entity);
|
||||||
|
entity.remove(RemovalReason.UNLOADED_WITH_PLAYER);
|
||||||
|
|
||||||
|
player.level().playSound(null, player.getOnPos(), SoundEvents.ARMOR_EQUIP_GENERIC.value(), SoundSource.AMBIENT, 1.0f, 0.5f);
|
||||||
|
CarryOnDataManager.setCarryData(player, carry);
|
||||||
|
player.swing(InteractionHand.MAIN_HAND, true);
|
||||||
|
if (!player.isCreative() || Constants.COMMON_CONFIG.settings.slownessInCreative)
|
||||||
|
player.addEffect(new MobEffectInstance(MobEffects.SLOWNESS, 100000000, CarryOnCommon.potionLevel(carry, player.level()), false, false));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends Comparable<T>> boolean hasPropertyType(BlockState state, Property<T> prop) {
|
||||||
|
for (var p : state.getProperties()) {
|
||||||
|
if(p.getValueClass().equals(prop.getValueClass()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,388 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.common.carry;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
import net.minecraft.sounds.SoundSource;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.effect.MobEffects;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.animal.equine.Horse;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||||
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
|
import net.minecraft.world.level.gamerules.GameRules;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData.CarryType;
|
||||||
|
import tschipp.carryon.common.config.ListHandler;
|
||||||
|
import tschipp.carryon.common.scripting.CarryOnScript.ScriptEffects;
|
||||||
|
import tschipp.carryon.networking.clientbound.ClientboundStartRidingOtherPlayerPacket;
|
||||||
|
import tschipp.carryon.platform.Services;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
public class PlacementHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
public static boolean tryPlaceBlock(ServerPlayer player, BlockPos pos, Direction facing, @Nullable BiFunction<BlockPos, BlockState, Boolean> placementCallback)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if (!carry.isCarrying(CarryOnData.CarryType.BLOCK))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (player.tickCount == carry.getTick())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Level level = player.level();
|
||||||
|
BlockState state = carry.getBlock();
|
||||||
|
|
||||||
|
BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos));
|
||||||
|
|
||||||
|
if (!level.getBlockState(pos).canBeReplaced(context))
|
||||||
|
pos = pos.relative(facing);
|
||||||
|
|
||||||
|
context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos));
|
||||||
|
|
||||||
|
BlockEntity blockEntity = carry.getBlockEntity(pos, level.registryAccess());
|
||||||
|
|
||||||
|
state = getPlacementState(state, player, context, pos);
|
||||||
|
|
||||||
|
boolean canPlace = state.canSurvive(level, pos) && level.mayInteract(player, pos) && level.getBlockState(pos).canBeReplaced(context) && level.isUnobstructed(state, pos, CollisionContext.of(player));
|
||||||
|
if (!canPlace) {
|
||||||
|
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.LAVA_POP, SoundSource.PLAYERS, 0.5F, 0.5F);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean doPlace = placementCallback == null || placementCallback.apply(pos, state);
|
||||||
|
|
||||||
|
if (!doPlace)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(level.isOutsideBuildHeight(pos))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (carry.getActiveScript().isPresent()) {
|
||||||
|
ScriptEffects effects = carry.getActiveScript().get().scriptEffects();
|
||||||
|
String cmd = effects.commandPlace();
|
||||||
|
if (!cmd.isEmpty())
|
||||||
|
player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
level.setBlockAndUpdate(pos, state);
|
||||||
|
if (blockEntity != null) {
|
||||||
|
blockEntity.setBlockState(state);
|
||||||
|
level.setBlockEntity(blockEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
level.updateNeighborsAt(pos.relative(Direction.DOWN), level.getBlockState(pos.relative(Direction.DOWN)).getBlock());
|
||||||
|
carry.clear();
|
||||||
|
CarryOnDataManager.setCarryData(player, carry);
|
||||||
|
player.playSound(state.getSoundType().getPlaceSound(), 1.0f, 0.5f);
|
||||||
|
level.playSound(null, pos, state.getSoundType().getPlaceSound(), SoundSource.BLOCKS, 1.0f, 0.5f);
|
||||||
|
player.swing(InteractionHand.MAIN_HAND, true);
|
||||||
|
player.removeEffect(MobEffects.SLOWNESS);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BlockState getPlacementState(BlockState state, ServerPlayer player, BlockPlaceContext context, BlockPos pos)
|
||||||
|
{
|
||||||
|
BlockState placementState = state.getBlock().getStateForPlacement(context);
|
||||||
|
if (placementState == null || placementState.getBlock() != state.getBlock())
|
||||||
|
placementState = state;
|
||||||
|
|
||||||
|
for (var prop : placementState.getProperties()) {
|
||||||
|
if (prop.getValueClass() == Direction.class)
|
||||||
|
state = updateProperty(state, placementState, prop);
|
||||||
|
if (prop.getValueClass() == Direction.Axis.class)
|
||||||
|
state = updateProperty(state, placementState, prop);
|
||||||
|
//This is needed for certain blocks, otherwise we get problems like chests not connecting
|
||||||
|
if (ListHandler.isPropertyException(prop)) {
|
||||||
|
state = updateProperty(state, placementState, prop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockState updatedState = Block.updateFromNeighbourShapes(state, player.level(), pos);
|
||||||
|
if (updatedState.getBlock() == state.getBlock())
|
||||||
|
state = updatedState;
|
||||||
|
|
||||||
|
if (placementState.hasProperty(BlockStateProperties.WATERLOGGED) && state.hasProperty(BlockStateProperties.WATERLOGGED))
|
||||||
|
state = state.setValue(BlockStateProperties.WATERLOGGED, placementState.getValue(BlockStateProperties.WATERLOGGED));
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends Comparable<T>> BlockState updateProperty(BlockState state, BlockState otherState, Property<T> prop)
|
||||||
|
{
|
||||||
|
var val = otherState.getValue(prop);
|
||||||
|
return state.setValue(prop, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean tryPlaceEntity(ServerPlayer player, BlockPos pos, Direction facing, @Nullable BiFunction<Vec3, Entity, Boolean> placementCallback)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
|
||||||
|
if (!carry.isCarrying(CarryType.ENTITY) && !carry.isCarrying(CarryType.PLAYER))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (player.tickCount == carry.getTick())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Level level = player.level();
|
||||||
|
|
||||||
|
BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos));
|
||||||
|
if (!level.getBlockState(pos).canBeReplaced(context)) {
|
||||||
|
pos = pos.relative(facing);
|
||||||
|
context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(player.position(), facing, pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!level.getBlockState(pos).canBeReplaced(context)) {
|
||||||
|
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.LAVA_POP, SoundSource.PLAYERS, 0.5F, 0.5F);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 placementPos = Vec3.atBottomCenterOf(pos);
|
||||||
|
|
||||||
|
if (carry.isCarrying(CarryType.PLAYER)) {
|
||||||
|
Entity otherPlayer = carry.getCarryingPlayer(level);
|
||||||
|
player.ejectPassengers();
|
||||||
|
Services.PLATFORM.sendPacketToAllPlayers(Constants.PACKET_ID_START_RIDING_OTHER, new ClientboundStartRidingOtherPlayerPacket(player.getId(), otherPlayer.getId(), false), player.level());
|
||||||
|
carry.clear();
|
||||||
|
CarryOnDataManager.setCarryData(player, carry);
|
||||||
|
otherPlayer.teleportTo(placementPos.x, placementPos.y, placementPos.z);
|
||||||
|
player.swing(InteractionHand.MAIN_HAND, true);
|
||||||
|
player.removeEffect(MobEffects.SLOWNESS);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity entity = carry.getEntity(level);
|
||||||
|
entity.setPos(placementPos);
|
||||||
|
|
||||||
|
boolean doPlace = placementCallback == null || placementCallback.apply(placementPos, entity);
|
||||||
|
if (!doPlace)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (carry.getActiveScript().isPresent()) {
|
||||||
|
ScriptEffects effects = carry.getActiveScript().get().scriptEffects();
|
||||||
|
String cmd = effects.commandPlace();
|
||||||
|
if (!cmd.isEmpty())
|
||||||
|
player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
level.addFreshEntity(entity);
|
||||||
|
if (entity instanceof Mob mob)
|
||||||
|
mob.playAmbientSound();
|
||||||
|
|
||||||
|
player.swing(InteractionHand.MAIN_HAND, true);
|
||||||
|
carry.clear();
|
||||||
|
CarryOnDataManager.setCarryData(player, carry);
|
||||||
|
player.removeEffect(MobEffects.SLOWNESS);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void tryStackEntity(ServerPlayer player, Entity entityClicked)
|
||||||
|
{
|
||||||
|
if(!Constants.COMMON_CONFIG.settings.stackableEntities)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if (!carry.isCarrying(CarryType.ENTITY) && !carry.isCarrying(CarryType.PLAYER))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Level level = player.level();
|
||||||
|
Entity entityHeld;
|
||||||
|
if (carry.isCarrying(CarryType.ENTITY))
|
||||||
|
entityHeld = carry.getEntity(level);
|
||||||
|
else
|
||||||
|
entityHeld = player.getFirstPassenger();
|
||||||
|
|
||||||
|
if(entityHeld == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
double sizeHeldEntity = entityHeld.getBbHeight() * entityHeld.getBbWidth();
|
||||||
|
double distance = entityClicked.blockPosition().distSqr(player.blockPosition());
|
||||||
|
Entity lowestEntity = entityClicked.getRootVehicle();
|
||||||
|
int numPassengers = getPassengerCount(lowestEntity);
|
||||||
|
if (numPassengers < Constants.COMMON_CONFIG.settings.maxEntityStackLimit - 1) {
|
||||||
|
Entity topEntity = getTopPassenger(lowestEntity);
|
||||||
|
|
||||||
|
if (topEntity == entityHeld)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ListHandler.isStackingPermitted(topEntity)) {
|
||||||
|
double sizeEntity = topEntity.getBbHeight() * topEntity.getBbWidth();
|
||||||
|
if (!Constants.COMMON_CONFIG.settings.entitySizeMattersStacking || sizeHeldEntity <= sizeEntity) {
|
||||||
|
if (topEntity instanceof Horse horse)
|
||||||
|
horse.setTamed(true);
|
||||||
|
|
||||||
|
if (distance < 6) {
|
||||||
|
double tempX = entityClicked.getX();
|
||||||
|
double tempY = entityClicked.getY();
|
||||||
|
double tempZ = entityClicked.getZ();
|
||||||
|
if (carry.isCarrying(CarryType.ENTITY)) {
|
||||||
|
entityHeld.setPos(tempX, tempY + 2.6, tempZ);
|
||||||
|
level.addFreshEntity(entityHeld);
|
||||||
|
entityHeld.teleportTo(tempX, tempY, tempZ);
|
||||||
|
}
|
||||||
|
entityHeld.startRiding(topEntity, false,false);
|
||||||
|
} else {
|
||||||
|
if (carry.isCarrying(CarryType.ENTITY)) {
|
||||||
|
entityHeld.setPos(entityClicked.getX(), entityClicked.getY(), entityClicked.getZ());
|
||||||
|
level.addFreshEntity(entityHeld);
|
||||||
|
}
|
||||||
|
entityHeld.startRiding(topEntity, false,false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (carry.getActiveScript().isPresent()) {
|
||||||
|
ScriptEffects effects = carry.getActiveScript().get().scriptEffects();
|
||||||
|
String cmd = effects.commandPlace();
|
||||||
|
if (!cmd.isEmpty())
|
||||||
|
player.level().getServer().getCommands().performPrefixedCommand(player.level().getServer().createCommandSourceStack(), "/execute as " + player.getGameProfile().name() + " run " + cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
player.swing(InteractionHand.MAIN_HAND, true);
|
||||||
|
carry.clear();
|
||||||
|
CarryOnDataManager.setCarryData(player, carry);
|
||||||
|
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.HORSE_SADDLE, SoundSource.PLAYERS, 0.5F, 1.5F);
|
||||||
|
player.removeEffect(MobEffects.SLOWNESS);
|
||||||
|
} else {
|
||||||
|
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.LAVA_POP, SoundSource.PLAYERS, 0.5F, 0.5F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.LAVA_POP, SoundSource.PLAYERS, 0.5F, 0.5F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void placeCarriedOnDeath(ServerPlayer oldPlayer, ServerPlayer newPlayer, boolean died)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(oldPlayer);
|
||||||
|
if (oldPlayer.level().getGameRules().get(GameRules.KEEP_INVENTORY) || !died) {
|
||||||
|
if (!carry.isCarrying(CarryType.PLAYER)) {
|
||||||
|
CarryOnDataManager.setCarryData(newPlayer, carry);
|
||||||
|
newPlayer.getInventory().setSelectedSlot(oldPlayer.getInventory().getSelectedSlot());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
placeCarried(oldPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void placeCarried(ServerPlayer player)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if (carry.isCarrying(CarryType.ENTITY)) {
|
||||||
|
Entity entity = carry.getEntity(player.level());
|
||||||
|
entity.setPos(player.position());
|
||||||
|
player.level().addFreshEntity(entity);
|
||||||
|
} else if (carry.isCarrying(CarryType.BLOCK)) {
|
||||||
|
BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(Vec3.atCenterOf(player.blockPosition()), Direction.DOWN, player.blockPosition()));
|
||||||
|
BlockState state = getPlacementState(carry.getBlock(), player, context, player.blockPosition());
|
||||||
|
BlockPos pos = getDeathPlacementPos(state, player);
|
||||||
|
BlockEntity blockEntity = carry.getBlockEntity(pos, player.level().registryAccess());
|
||||||
|
player.level().setBlock(pos, state, 3);
|
||||||
|
if (blockEntity != null)
|
||||||
|
player.level().setBlockEntity(blockEntity);
|
||||||
|
} else if (carry.isCarrying(CarryType.PLAYER)) {
|
||||||
|
player.ejectPassengers();
|
||||||
|
}
|
||||||
|
carry.clear();
|
||||||
|
CarryOnDataManager.setCarryData(player, carry);
|
||||||
|
player.removeEffect(MobEffects.SLOWNESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BlockPos getDeathPlacementPos(BlockState state, ServerPlayer player)
|
||||||
|
{
|
||||||
|
BlockPos p = player.blockPosition();
|
||||||
|
|
||||||
|
int DISTANCE = 15;
|
||||||
|
|
||||||
|
List<BlockPos> potentialPositions = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int j = 0; j < DISTANCE * 2; j++) {
|
||||||
|
for (int i = 0; i < DISTANCE * 2; i++) {
|
||||||
|
for (int k = 0; k < DISTANCE * 2; k++) {
|
||||||
|
int x = i % 2 == 0 ? i / 2 : -(i / 2);
|
||||||
|
int y = j % 2 == 0 ? j / 2 : -(j / 2);
|
||||||
|
int z = k % 2 == 0 ? k / 2 : -(k / 2);
|
||||||
|
potentialPositions.add(new BlockPos(p.getX() + x, p.getY() + y, p.getZ() + z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
potentialPositions.sort(Comparator.comparingDouble(posA -> player.distanceToSqr(posA.getCenter())));
|
||||||
|
|
||||||
|
for(BlockPos potential : potentialPositions)
|
||||||
|
{
|
||||||
|
BlockPlaceContext context = new BlockPlaceContext(player, InteractionHand.MAIN_HAND, ItemStack.EMPTY, BlockHitResult.miss(Vec3.atCenterOf(potential), Direction.DOWN, potential));
|
||||||
|
boolean canPlace = state.canSurvive(player.level(), potential) && player.level().getBlockState(potential).canBeReplaced(context) && player.level().isUnobstructed(state, potential, CollisionContext.of(player));
|
||||||
|
|
||||||
|
if (canPlace)
|
||||||
|
return potential;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getPassengerCount(Entity entity)
|
||||||
|
{
|
||||||
|
int passengers = 0;
|
||||||
|
while (entity.isVehicle()) {
|
||||||
|
List<Entity> pass = entity.getPassengers();
|
||||||
|
if (!pass.isEmpty()) {
|
||||||
|
entity = pass.get(0);
|
||||||
|
passengers++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return passengers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity getTopPassenger(Entity entity)
|
||||||
|
{
|
||||||
|
Entity top = entity;
|
||||||
|
while (entity.isVehicle()) {
|
||||||
|
List<Entity> pass = entity.getPassengers();
|
||||||
|
if (!pass.isEmpty()) {
|
||||||
|
entity = pass.get(0);
|
||||||
|
top = entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.common.command;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import net.minecraft.commands.Commands;
|
||||||
|
import net.minecraft.commands.arguments.EntityArgument;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.permissions.Permission;
|
||||||
|
import net.minecraft.server.permissions.PermissionLevel;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.client.modeloverride.ModelOverride;
|
||||||
|
import tschipp.carryon.client.modeloverride.ModelOverrideHandler;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData.CarryType;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnDataManager;
|
||||||
|
import tschipp.carryon.common.carry.PlacementHandler;
|
||||||
|
import tschipp.carryon.common.pickupcondition.PickupCondition;
|
||||||
|
import tschipp.carryon.common.pickupcondition.PickupConditionHandler;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class CommandCarryOn
|
||||||
|
{
|
||||||
|
public static void register(CommandDispatcher<CommandSourceStack> dispatcher)
|
||||||
|
{
|
||||||
|
LiteralArgumentBuilder<CommandSourceStack> builder = Commands.literal("carryon")
|
||||||
|
|
||||||
|
.then(Commands.literal("debug").executes(cmd -> handleDebug(cmd.getSource())))
|
||||||
|
|
||||||
|
.then(Commands.literal("clear").executes(cmd -> handleClear(cmd.getSource(), Collections.singleton(cmd.getSource().getPlayerOrException()))))
|
||||||
|
|
||||||
|
.then(Commands.literal("clear").then(Commands.argument("target", EntityArgument.players()).requires(src -> src.permissions().hasPermission(new Permission.HasCommandLevel(PermissionLevel.GAMEMASTERS))).executes(cmd -> handleClear(cmd.getSource(), EntityArgument.getPlayers(cmd, "target")))))
|
||||||
|
|
||||||
|
.then(Commands.literal("place").requires(src -> src.permissions().hasPermission(new Permission.HasCommandLevel(PermissionLevel.GAMEMASTERS))).executes(cmd -> handlePlace(cmd.getSource(), Collections.singleton(cmd.getSource().getPlayerOrException()))))
|
||||||
|
|
||||||
|
.then(Commands.literal("place").then(Commands.argument("target", EntityArgument.players()).requires(src -> src.permissions().hasPermission(new Permission.HasCommandLevel(PermissionLevel.GAMEMASTERS))).executes(cmd -> handlePlace(cmd.getSource(), EntityArgument.getPlayers(cmd, "target")))))
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
dispatcher.register(builder);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int handleDebug(CommandSourceStack source)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (source.getEntityOrException() != null)
|
||||||
|
{
|
||||||
|
ServerPlayer player = source.getPlayerOrException();
|
||||||
|
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if (carry.isCarrying(CarryType.BLOCK))
|
||||||
|
{
|
||||||
|
BlockState block = carry.getBlock();
|
||||||
|
log(source,"Block: " + block.getBlock());
|
||||||
|
log(source,"BlockState: " + block);
|
||||||
|
log(source,"NBT: " + carry.getNbt());
|
||||||
|
|
||||||
|
Optional<ModelOverride> ov = ModelOverrideHandler.getModelOverride(block, carry.getContentNbt());
|
||||||
|
if(ov.isPresent())
|
||||||
|
log(source, "Override Model: " + ov.get().getRenderObject());
|
||||||
|
|
||||||
|
Optional<PickupCondition> cond = PickupConditionHandler.getPickupCondition(block);
|
||||||
|
if(cond.isPresent())
|
||||||
|
log(source, "Custom Pickup Condition: " + cond.get().getCondition());
|
||||||
|
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (carry.isCarrying(CarryType.ENTITY))
|
||||||
|
{
|
||||||
|
Entity entity = carry.getEntity(player.level());
|
||||||
|
log(source,"Entity: " + entity);
|
||||||
|
log(source,"Entity Name: " + entity.getType());
|
||||||
|
log(source,"NBT: " + carry.getNbt());
|
||||||
|
|
||||||
|
Optional<PickupCondition> cond = PickupConditionHandler.getPickupCondition(entity);
|
||||||
|
if(cond.isPresent())
|
||||||
|
log(source, "Custom Pickup Condition: " + cond.get().getCondition());
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if(carry.isCarrying(CarryType.PLAYER))
|
||||||
|
{
|
||||||
|
log(source, "Carrying Player.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (CommandSyntaxException e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int handleClear(CommandSourceStack source, Collection<ServerPlayer> players)
|
||||||
|
{
|
||||||
|
int cleared = 0;
|
||||||
|
for (ServerPlayer player : players)
|
||||||
|
{
|
||||||
|
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
carry.clear();
|
||||||
|
CarryOnDataManager.setCarryData(player, carry);
|
||||||
|
|
||||||
|
cleared++;
|
||||||
|
}
|
||||||
|
int finalCleared = cleared;
|
||||||
|
|
||||||
|
if (cleared != 1) {
|
||||||
|
source.sendSuccess(() -> Component.literal("Cleared " + finalCleared + " Items!"), true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
source.sendSuccess(() -> Component.literal("Cleared " + finalCleared + " Item!"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int handlePlace(CommandSourceStack source, Collection<ServerPlayer> players)
|
||||||
|
{
|
||||||
|
int cleared = 0;
|
||||||
|
for (ServerPlayer player : players)
|
||||||
|
{
|
||||||
|
PlacementHandler.placeCarried(player);
|
||||||
|
cleared++;
|
||||||
|
}
|
||||||
|
int finalCleared = cleared;
|
||||||
|
|
||||||
|
if (cleared != 1) {
|
||||||
|
source.sendSuccess(() -> Component.literal("Placed " + finalCleared + " Items!"), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
source.sendSuccess(() -> Component.literal("Placed " + finalCleared + " Item!"), true);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void log(CommandSourceStack source, String toLog)
|
||||||
|
{
|
||||||
|
source.sendSuccess(() -> Component.literal(toLog), true);
|
||||||
|
Constants.LOG.info(toLog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,379 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.common.config;
|
||||||
|
|
||||||
|
import tschipp.carryon.config.PropertyType;
|
||||||
|
import tschipp.carryon.config.annotations.Category;
|
||||||
|
import tschipp.carryon.config.annotations.Config;
|
||||||
|
import tschipp.carryon.config.annotations.Property;
|
||||||
|
|
||||||
|
public class CarryConfig
|
||||||
|
{
|
||||||
|
|
||||||
|
@Config("carryon-common")
|
||||||
|
public static class Common
|
||||||
|
{
|
||||||
|
//Settings
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.CATEGORY,
|
||||||
|
description = "General Settings"
|
||||||
|
)
|
||||||
|
public Settings settings = new Settings();
|
||||||
|
|
||||||
|
@Category(value="settings", translation = "carryon.category.settings")
|
||||||
|
public static class Settings
|
||||||
|
{
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.DOUBLE,
|
||||||
|
description = "Maximum distance from where Blocks and Entities can be picked up",
|
||||||
|
minD = 0
|
||||||
|
)
|
||||||
|
public double maxDistance = 2.5;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.DOUBLE,
|
||||||
|
description = "Max width of entities that can be picked up in survival mode",
|
||||||
|
minD = 0,
|
||||||
|
maxD = 10
|
||||||
|
)
|
||||||
|
public double maxEntityWidth = 1.5;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.DOUBLE,
|
||||||
|
description = "Max height of entities that can be picked up in survival mode",
|
||||||
|
minD = 0,
|
||||||
|
maxD = 10
|
||||||
|
)
|
||||||
|
public double maxEntityHeight = 2.5;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.DOUBLE,
|
||||||
|
description = "Slowness multiplier for blocks",
|
||||||
|
minD = 0
|
||||||
|
)
|
||||||
|
public double blockSlownessMultiplier = 1;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.DOUBLE,
|
||||||
|
description = "Slowness multiplier for entities",
|
||||||
|
minD = 0
|
||||||
|
)
|
||||||
|
public double entitySlownessMultiplier = 1;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.INT,
|
||||||
|
description = "Maximum stack limit for entities",
|
||||||
|
min = 1
|
||||||
|
)
|
||||||
|
public int maxEntityStackLimit = 10;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "More complex Tile Entities slow down the player more"
|
||||||
|
)
|
||||||
|
public boolean heavyTiles = true;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Allow all blocks to be picked up, not just Tile Entites. White/Blacklist will still be respected."
|
||||||
|
)
|
||||||
|
public boolean pickupAllBlocks = false;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Whether Blocks and Entities slow the creative player down when carried"
|
||||||
|
)
|
||||||
|
public boolean slownessInCreative = true;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Whether hostile mobs should be able to picked up in survival mode"
|
||||||
|
)
|
||||||
|
public boolean pickupHostileMobs = false;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Larger Entities slow down the player more"
|
||||||
|
)
|
||||||
|
public boolean heavyEntities = true;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Allow babies to be carried even when adult mob is blacklisted (or not whitelisted)"
|
||||||
|
)
|
||||||
|
public boolean allowBabies = false;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Use Whitelist instead of Blacklist for Blocks"
|
||||||
|
)
|
||||||
|
public boolean useWhitelistBlocks = false;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Use Whitelist instead of Blacklist for Entities"
|
||||||
|
)
|
||||||
|
public boolean useWhitelistEntities = false;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Use Whitelist instead of Blacklist for Stacking"
|
||||||
|
)
|
||||||
|
public boolean useWhitelistStacking = false;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Whether the player can hit blocks and entities while carrying or not"
|
||||||
|
)
|
||||||
|
public boolean hitWhileCarrying = false;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Whether the player drops the carried object when hit or not"
|
||||||
|
)
|
||||||
|
public boolean dropCarriedWhenHit = false;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Use custom Pickup Scripts. Having this set to false, will not allow you to run scripts, but will increase your performance"
|
||||||
|
)
|
||||||
|
public boolean useScripts = false;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Allows entities to be stacked on top of each other"
|
||||||
|
)
|
||||||
|
public boolean stackableEntities = true;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Whether entities' size matters when stacking or not. This means that larger entities cannot be stacked on smaller ones"
|
||||||
|
)
|
||||||
|
public boolean entitySizeMattersStacking = true;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.STRING_ARRAY,
|
||||||
|
description = "Usually all the block state information is retained when placing a block that was picked up. But some information is changed to a modified property, like rotation or orientation. In this list, add additional properties that should NOT be saved and instead be updated when placed. Format: modid:block[propertyname]. Note: You don't need to add an entry for every subtype of a same block. For example, we only add an entry for one type of slab, but the change is applied to all slabs.",
|
||||||
|
validationRegex = "([a-zA-Z0-9_]+:[a-zA-Z0-9_]+)\\[([a-zA-Z0-9_,]+)\\]"
|
||||||
|
)
|
||||||
|
public String[] placementStateExceptions = {
|
||||||
|
"minecraft:chest[type]",
|
||||||
|
"minecraft:stone_button[face]",
|
||||||
|
"minecraft:vine[north,east,south,west,up]",
|
||||||
|
"minecraft:creeper_head[rotation]",
|
||||||
|
"minecraft:glow_lichen[north,east,south,west,up,down]",
|
||||||
|
"minecraft:oak_sign[rotation]",
|
||||||
|
"minecraft:oak_trapdoor[half]",
|
||||||
|
};
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Whether Players can be picked up. Creative players can't be picked up in Survival Mode"
|
||||||
|
)
|
||||||
|
public boolean pickupPlayers = true;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Whether players in Survival Mode can pick up unbreakable blocks. Creative players always can."
|
||||||
|
)
|
||||||
|
public boolean pickupUnbreakableBlocks = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.CATEGORY,
|
||||||
|
description = "Whitelist. Read about the format here: https://github.com/Tschipp/CarryOn/wiki/Black---and-Whitelist-Config"
|
||||||
|
)
|
||||||
|
|
||||||
|
//Whitelist
|
||||||
|
public Whitelist whitelist = new Whitelist();
|
||||||
|
|
||||||
|
@Category(value="whitelist", translation = "carryon.category.whitelist")
|
||||||
|
public static class Whitelist
|
||||||
|
{
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.STRING_ARRAY,
|
||||||
|
description = "Entities that CAN be picked up (useWhitelistEntities must be true)",
|
||||||
|
validationRegex = "(#?[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]*(?:\\*|[a-zA-Z0-9_]*)(?:\\*|[a-zA-Z0-9_]*)?)"
|
||||||
|
)
|
||||||
|
public String[] allowedEntities = {};
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.STRING_ARRAY,
|
||||||
|
description = "Blocks that CAN be picked up (useWhitelistBlocks must be true)",
|
||||||
|
validationRegex = "(#?[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]*(?:\\*|[a-zA-Z0-9_]*)(?:\\*|[a-zA-Z0-9_]*)?)"
|
||||||
|
)
|
||||||
|
public String[] allowedBlocks = {};
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.STRING_ARRAY,
|
||||||
|
description = "Entities that CAN have other entities stacked on top of them (useWhitelistStacking must be true)",
|
||||||
|
validationRegex = "(#?[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]*(?:\\*|[a-zA-Z0-9_]*)(?:\\*|[a-zA-Z0-9_]*)?)"
|
||||||
|
)
|
||||||
|
public String[] allowedStacking = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
//Blacklist
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.CATEGORY,
|
||||||
|
description = "Blacklist. Read about the format here: https://github.com/Tschipp/CarryOn/wiki/Black---and-Whitelist-Config"
|
||||||
|
)
|
||||||
|
public Blacklist blacklist = new Blacklist();
|
||||||
|
|
||||||
|
@Category(value="blacklist", translation = "carryon.category.blacklist")
|
||||||
|
public static class Blacklist
|
||||||
|
{
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.STRING_ARRAY,
|
||||||
|
description = "Blocks that cannot be picked up",
|
||||||
|
validationRegex = "(#?[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]*(?:\\*|[a-zA-Z0-9_]*)(?:\\*|[a-zA-Z0-9_]*)?)"
|
||||||
|
)
|
||||||
|
public String[] forbiddenTiles = {
|
||||||
|
"#forge:immovable", "#forge:relocation_not_supported", "#neoforge:immovable", "#neoforge:relocation_not_supported", "minecraft:end_portal", "minecraft:piston_head",
|
||||||
|
"#c:relocation_not_supported",
|
||||||
|
"minecraft:end_gateway", "minecraft:tall_grass", "minecraft:large_fern", "minecraft:peony",
|
||||||
|
"minecraft:rose_bush", "minecraft:lilac", "minecraft:sunflower", "minecraft:*_bed",
|
||||||
|
"minecraft:*_door", "minecraft:big_dripleaf_stem", "minecraft:waterlily", "minecraft:cake",
|
||||||
|
"minecraft:nether_portal", "minecraft:tall_seagrass", "animania:block_trough",
|
||||||
|
"animania:block_invisiblock", "colossalchests:*", "ic2:*", "bigreactors:*", "forestry:*",
|
||||||
|
"tconstruct:*", "rustic:*", "botania:*", "astralsorcery:*", "quark:colored_bed_*",
|
||||||
|
"immersiveengineering:*", "embers:block_furnace", "embers:ember_bore",
|
||||||
|
"embers:ember_activator", "embers:mixer", "embers:heat_coil", "embers:large_tank",
|
||||||
|
"embers:crystal_cell", "embers:alchemy_pedestal", "embers:boiler", "embers:combustor",
|
||||||
|
"embers:catalzyer", "embers:field_chart", "embers:inferno_forge",
|
||||||
|
"storagedrawers:framingtable", "skyresources:*", "lootbags:*", "exsartagine:*",
|
||||||
|
"aquamunda:tank", "opencomputers:*", "malisisdoors:*", "industrialforegoing:*",
|
||||||
|
"minecolonies:*", "thaumcraft:pillar*", "thaumcraft:infernal_furnace",
|
||||||
|
"thaumcraft:placeholder*", "thaumcraft:infusion_matrix", "thaumcraft:golem_builder",
|
||||||
|
"thaumcraft:thaumatorium*", "magneticraft:oil_heater", "magneticraft:solar_panel",
|
||||||
|
"magneticraft:steam_engine", "magneticraft:shelving_unit", "magneticraft:grinder",
|
||||||
|
"magneticraft:sieve", "magneticraft:solar_tower", "magneticraft:solar_mirror",
|
||||||
|
"magneticraft:container", "magneticraft:pumpjack", "magneticraft:solar_panel",
|
||||||
|
"magneticraft:refinery", "magneticraft:oil_heater", "magneticraft:hydraulic_press",
|
||||||
|
"magneticraft:multiblock_gap", "refinedstorage:*", "mcmultipart:*", "enderstorage:*",
|
||||||
|
"betterstorage:*", "practicallogistics2:*", "wearablebackpacks:*", "rftools:screen",
|
||||||
|
"rftools:creative_screen", "create:*", "magic_doorknob:*", "iceandfire:*", "ftbquests:*",
|
||||||
|
"waystones:*", "contact:*", "framedblocks:*", "securitycraft:*", "forgemultipartcbe:*", "integrateddynamics:cable",
|
||||||
|
"mekanismgenerators:wind_generator", "cookingforblockheads:cabinet", "cookingforblockheads:corner", "cookingforblockheads:counter",
|
||||||
|
"cookingforblockheads:oven", "cookingforblockheads:toaster", "cookingforblockheads:milk_jar", "cookingforblockheads:cow_jar",
|
||||||
|
"cookingforblockheads:fruit_basket", "cookingforblockheads:cooking_table", "cookingforblockheads:fridge", "cookingforblockheads:sink",
|
||||||
|
"chipped:*", "irons_spellbooks:*", "create*:*", "simple_pipes:*", "libmultipart:*", "quark:tiny_potato", "ait:*",
|
||||||
|
"vampirism:*", "extrastorage:*", "relics:researching_table", "sophisticatedstorage:*chest",
|
||||||
|
"powah:*", "advancementtrophies:trophy", "mekanismgenerators:heat_generator", "mna:filler_block", "create_enchantment_industry:*", "graveyard:*", "immersivepetroleum:*",
|
||||||
|
"tardis:interior_door", "cuffed:*", "littletiles:*",
|
||||||
|
"butchersdelight:*", "irons_spellbooks:*", "extended_drawers:*", "functionalstorage:*", "sophisticatedstorage:*", "farmersdelight:*",
|
||||||
|
"modern_industrialization:*_cable",
|
||||||
|
"modern_industrialization:item_pipe",
|
||||||
|
"modern_industrialization:*_item_pipe",
|
||||||
|
"modern_industrialization:fluid_pipe",
|
||||||
|
"modern_industrialization:*_fluid_pipe",
|
||||||
|
"yigd:*", "domum_ornamentum:*", "connectiblechains:*",
|
||||||
|
"cobblemon:*", "snowrealmagic:*", "forbidden_arcanus:black_hole", "domum_ornamentum:*", "sgjourney:*", "copycats:*", "expandedstorage:*", "replication:*"
|
||||||
|
};
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.STRING_ARRAY,
|
||||||
|
description = "Entities that cannot be picked up",
|
||||||
|
validationRegex = "(#?[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]*(?:\\*|[a-zA-Z0-9_]*)(?:\\*|[a-zA-Z0-9_]*)?)"
|
||||||
|
)
|
||||||
|
public String[] forbiddenEntities = {
|
||||||
|
"#c:capturing_not_supported", "#c:teleporting_not_supported",
|
||||||
|
"minecraft:end_crystal", "minecraft:ender_dragon", "minecraft:ghast", "minecraft:fireball", "minecraft:small_fireball", "minecraft:whither_skull",
|
||||||
|
"minecraft:shulker", "minecraft:leash_knot", "minecraft:armor_stand", "minecraft:whither_skull_dangerous", "minecraft:dragon_fireball",
|
||||||
|
"minecraft:item_frame", "minecraft:painting", "minecraft:shulker_bullet", "minecraft:evoker_fangs", "minecraft:glow_item_frame", "minecraft:tnt", "minecraft:trident", "minecraft:arrow", "minecraft:spectral_arrow",
|
||||||
|
"minecraft:interaction", "minecraft:marker", "minecraft:block_display", "minecraft:item_display", "minecraft:text_display",
|
||||||
|
"animania:hamster", "animania:ferret*", "animania:hedgehog*", "animania:cart",
|
||||||
|
"animania:wagon", "mynko:*", "pixelmon:*", "mocreatures:*", "quark:totem", "vehicle:*",
|
||||||
|
"securitycraft:*", "taterzens:npc", "easy_npc:*", "bodiesbodies:dead_body", "littletiles:*",
|
||||||
|
"connectiblechains:*", "cobblemon:*", "create:*", "swem:*", "toms_mobs:*"
|
||||||
|
};
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.STRING_ARRAY,
|
||||||
|
description = "Entities that cannot have other entities stacked on top of them",
|
||||||
|
validationRegex = "(#?[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]*(?:\\*|[a-zA-Z0-9_]*)(?:\\*|[a-zA-Z0-9_]*)?)"
|
||||||
|
)
|
||||||
|
public String[] forbiddenStacking = {
|
||||||
|
"minecraft:horse",
|
||||||
|
"minecraft:ender_dragon"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//Custom Pickup Conditions
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.CATEGORY,
|
||||||
|
description = "Custom Pickup Conditions. Read about the format here: https://github.com/Tschipp/CarryOn/wiki/Custom-Pickup-Condition-Config"
|
||||||
|
)
|
||||||
|
public CustomPickupConditions customPickupConditions = new CustomPickupConditions();
|
||||||
|
|
||||||
|
@Category(value="customPickupConditions", translation = "carryon.category.custompickupconditions")
|
||||||
|
public static class CustomPickupConditions
|
||||||
|
{
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.STRING_ARRAY,
|
||||||
|
description = "Custom Pickup Conditions for Blocks",
|
||||||
|
validationRegex = "([a-zA-Z0-9_*\\-:]+(?:\\[[^\\]]*\\])?)\\(([\\w_]+)\\)"
|
||||||
|
)
|
||||||
|
public String[] customPickupConditionsBlocks = {};
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.STRING_ARRAY,
|
||||||
|
description = "Custom Pickup Conditions for Entities",
|
||||||
|
validationRegex = "([a-zA-Z0-9_*\\-:]+(?:\\[[^\\]]*\\])?)\\(([\\w_]+)\\)"
|
||||||
|
)
|
||||||
|
public String[] customPickupConditionsEntities = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Config("carryon-client")
|
||||||
|
public static class Client
|
||||||
|
{
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "If the front of the Tile Entities should face the player or should face outward"
|
||||||
|
)
|
||||||
|
public boolean facePlayer = false;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "If Entities should be rotated sideways when carried"
|
||||||
|
)
|
||||||
|
public boolean rotateEntitiesSideways = false;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.BOOLEAN,
|
||||||
|
description = "Arms should render on sides when carrying. Set to false if you experience issues with mods that replace the player model (like MoBends, etc)"
|
||||||
|
)
|
||||||
|
public boolean renderArms = true;
|
||||||
|
|
||||||
|
@Property(
|
||||||
|
type = PropertyType.STRING_ARRAY,
|
||||||
|
description = "Model Overrides based on NBT or Meta. Advanced users only! Read about the format here: https://github.com/Tschipp/CarryOn/wiki/Model-Override-Config",
|
||||||
|
validationRegex = "([a-zA-Z0-9_]+:[a-zA-Z0-9_]+(?:\\[[^\\]]*\\])?(?:\\{[^}]*\\})?)(?:;(\\d+))?->(?:\\((item|block)\\))?([a-zA-Z0-9_]+:[a-zA-Z0-9_]+(?:\\[[^\\]]*\\])?(?:\\{[^}]*\\})?)(?:;(\\d+))?"
|
||||||
|
)
|
||||||
|
public String[] modelOverrides = {
|
||||||
|
"minecraft:redstone_wire->(item)minecraft:redstone",
|
||||||
|
"minecraft:bamboo_sapling->(block)minecraft:bamboo",
|
||||||
|
"minecraft:candle_cake->(block)minecraft:cake"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,236 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.common.config;
|
||||||
|
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
import net.minecraft.tags.TagKey;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.utils.StringHelper;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ListHandler {
|
||||||
|
|
||||||
|
private static Set<String> FORBIDDEN_TILES = new HashSet<>();
|
||||||
|
private static Set<String> FORBIDDEN_ENTITIES = new HashSet<>();
|
||||||
|
private static Set<String> ALLOWED_ENTITIES = new HashSet<>();
|
||||||
|
private static Set<String> ALLOWED_TILES = new HashSet<>();
|
||||||
|
private static Set<String> FORBIDDEN_STACKING = new HashSet<>();
|
||||||
|
private static Set<String> ALLOWED_STACKING = new HashSet<>();
|
||||||
|
|
||||||
|
private static List<TagKey<Block>> FORBIDDEN_TILES_TAGS = new ArrayList<>();
|
||||||
|
private static List<TagKey<EntityType<?>>> FORBIDDEN_ENTITIES_TAGS = new ArrayList<>();
|
||||||
|
private static List<TagKey<EntityType<?>>> ALLOWED_ENTITIES_TAGS = new ArrayList<>();
|
||||||
|
private static List<TagKey<Block>> ALLOWED_TILES_TAGS = new ArrayList<>();
|
||||||
|
private static List<TagKey<EntityType<?>>> FORBIDDEN_STACKING_TAGS = new ArrayList<>();
|
||||||
|
private static List<TagKey<EntityType<?>>> ALLOWED_STACKING_TAGS = new ArrayList<>();
|
||||||
|
|
||||||
|
private static Set<Property<?>> PROPERTY_EXCEPTION_CLASSES = new HashSet<>();
|
||||||
|
|
||||||
|
public static boolean isPermitted(Block block)
|
||||||
|
{
|
||||||
|
if(Constants.COMMON_CONFIG.settings.useWhitelistBlocks)
|
||||||
|
return doCheck(block, ALLOWED_TILES, ALLOWED_TILES_TAGS);
|
||||||
|
else
|
||||||
|
return !doCheck(block, FORBIDDEN_TILES, FORBIDDEN_TILES_TAGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPermitted(Entity entity)
|
||||||
|
{
|
||||||
|
if(Constants.COMMON_CONFIG.settings.useWhitelistEntities)
|
||||||
|
return doCheck(entity, ALLOWED_ENTITIES, ALLOWED_ENTITIES_TAGS);
|
||||||
|
else
|
||||||
|
return !doCheck(entity, FORBIDDEN_ENTITIES, FORBIDDEN_ENTITIES_TAGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isStackingPermitted(Entity entity)
|
||||||
|
{
|
||||||
|
if(Constants.COMMON_CONFIG.settings.useWhitelistStacking)
|
||||||
|
return doCheck(entity, ALLOWED_STACKING, ALLOWED_STACKING_TAGS);
|
||||||
|
else
|
||||||
|
return !doCheck(entity, FORBIDDEN_STACKING, FORBIDDEN_STACKING_TAGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPropertyException(Property<?> prop)
|
||||||
|
{
|
||||||
|
return PROPERTY_EXCEPTION_CLASSES.contains(prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean doCheck(Block block, Set<String> regular, List<TagKey<Block>> tags)
|
||||||
|
{
|
||||||
|
String name = BuiltInRegistries.BLOCK.getKey(block).toString();
|
||||||
|
if(regular.contains(name))
|
||||||
|
return true;
|
||||||
|
for(TagKey<Block> tag : tags)
|
||||||
|
if(block.defaultBlockState().is(tag))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean doCheck(Entity entity, Set<String> regular, List<TagKey<EntityType<?>>> tags)
|
||||||
|
{
|
||||||
|
String name = BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString();
|
||||||
|
if(regular.contains(name))
|
||||||
|
return true;
|
||||||
|
for(TagKey<EntityType<?>> tag : tags)
|
||||||
|
if(entity.getType().is(tag))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void initConfigLists()
|
||||||
|
{
|
||||||
|
FORBIDDEN_ENTITIES.clear();
|
||||||
|
FORBIDDEN_ENTITIES_TAGS.clear();
|
||||||
|
FORBIDDEN_STACKING.clear();
|
||||||
|
FORBIDDEN_STACKING_TAGS.clear();
|
||||||
|
FORBIDDEN_TILES.clear();
|
||||||
|
FORBIDDEN_TILES_TAGS.clear();
|
||||||
|
ALLOWED_ENTITIES.clear();
|
||||||
|
ALLOWED_ENTITIES_TAGS.clear();
|
||||||
|
ALLOWED_STACKING.clear();
|
||||||
|
ALLOWED_STACKING_TAGS.clear();
|
||||||
|
ALLOWED_TILES.clear();
|
||||||
|
ALLOWED_TILES_TAGS.clear();
|
||||||
|
PROPERTY_EXCEPTION_CLASSES.clear();
|
||||||
|
|
||||||
|
Map<Identifier, TagKey<Block>> blocktags = BuiltInRegistries.BLOCK.listTagIds().collect(Collectors.toMap(t -> t.location(), t -> t));
|
||||||
|
Map<Identifier, TagKey<EntityType<?>>> entitytags = BuiltInRegistries.ENTITY_TYPE.listTagIds().collect(Collectors.toMap(t -> t.location(), t -> t));
|
||||||
|
|
||||||
|
List<String> forbidden = new ArrayList<>(List.of(Constants.COMMON_CONFIG.blacklist.forbiddenTiles));
|
||||||
|
forbidden.add("#carryon:block_blacklist");
|
||||||
|
addWithWildcards(forbidden, FORBIDDEN_TILES, BuiltInRegistries.BLOCK, blocktags, FORBIDDEN_TILES_TAGS);
|
||||||
|
|
||||||
|
List<String> forbiddenEntity = new ArrayList<>(List.of(Constants.COMMON_CONFIG.blacklist.forbiddenEntities));
|
||||||
|
forbiddenEntity.add("#carryon:entity_blacklist");
|
||||||
|
addWithWildcards(forbiddenEntity, FORBIDDEN_ENTITIES, BuiltInRegistries.ENTITY_TYPE, entitytags, FORBIDDEN_ENTITIES_TAGS);
|
||||||
|
|
||||||
|
List<String> allowedEntities = new ArrayList<>(List.of(Constants.COMMON_CONFIG.whitelist.allowedEntities));
|
||||||
|
allowedEntities.add("#carryon:entity_whitelist");
|
||||||
|
addWithWildcards(allowedEntities, ALLOWED_ENTITIES, BuiltInRegistries.ENTITY_TYPE, entitytags, ALLOWED_ENTITIES_TAGS);
|
||||||
|
|
||||||
|
List<String> allowedBlocks = new ArrayList<>(List.of(Constants.COMMON_CONFIG.whitelist.allowedBlocks));
|
||||||
|
allowedBlocks.add("#carryon:block_whitelist");
|
||||||
|
addWithWildcards(allowedBlocks, ALLOWED_TILES, BuiltInRegistries.BLOCK, blocktags, ALLOWED_TILES_TAGS);
|
||||||
|
|
||||||
|
List<String> forbiddenStacking = new ArrayList<>(List.of(Constants.COMMON_CONFIG.blacklist.forbiddenStacking));
|
||||||
|
forbiddenStacking.add("#carryon:stacking_blacklist");
|
||||||
|
addWithWildcards(forbiddenStacking, FORBIDDEN_STACKING, BuiltInRegistries.ENTITY_TYPE, entitytags, FORBIDDEN_STACKING_TAGS);
|
||||||
|
|
||||||
|
List<String> allowedStacking = new ArrayList<>(List.of(Constants.COMMON_CONFIG.whitelist.allowedStacking));
|
||||||
|
allowedStacking.add("#carryon:stacking_whitelist");
|
||||||
|
addWithWildcards(allowedStacking, ALLOWED_STACKING, BuiltInRegistries.ENTITY_TYPE, entitytags, ALLOWED_STACKING_TAGS);
|
||||||
|
|
||||||
|
for(String propString : Constants.COMMON_CONFIG.settings.placementStateExceptions)
|
||||||
|
{
|
||||||
|
if(!propString.contains("[") || !propString.contains("]"))
|
||||||
|
continue;
|
||||||
|
String name = propString.substring(0, propString.indexOf("["));
|
||||||
|
String props = propString.substring(propString.indexOf("[") + 1, propString.indexOf("]"));
|
||||||
|
Block blk = BuiltInRegistries.BLOCK.get(Identifier.parse(name)).get().value();
|
||||||
|
for(String propName : props.split(",")) {
|
||||||
|
for (Property<?> prop : blk.defaultBlockState().getProperties()) {
|
||||||
|
if (prop.getName().equals(propName))
|
||||||
|
PROPERTY_EXCEPTION_CLASSES.add(prop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> void addTag(String tag, Map<Identifier, TagKey<T>> tagMap, List<TagKey<T>> tags) {
|
||||||
|
String sub = tag.substring(1);
|
||||||
|
TagKey<T> t = tagMap.get(Identifier.parse(sub));
|
||||||
|
if (t != null)
|
||||||
|
tags.add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> void addWithWildcards(List<String> entries, Set<String> toAddTo, Registry<T> registry, Map<Identifier, TagKey<T>> tags, List<TagKey<T>> toAddTags) {
|
||||||
|
|
||||||
|
Identifier[] keys = registry.keySet().toArray(new Identifier[0]);
|
||||||
|
for (int i = 0; i < entries.size(); i++)
|
||||||
|
{
|
||||||
|
String curr = entries.get(i);
|
||||||
|
if (!curr.startsWith("#"))
|
||||||
|
{
|
||||||
|
if (curr.contains("*"))
|
||||||
|
{
|
||||||
|
String[] filter = curr.replace("*", ",").split(",");
|
||||||
|
|
||||||
|
for (Identifier key : keys)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (containsAll(key.toString(), filter))
|
||||||
|
{
|
||||||
|
toAddTo.add(key.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
toAddTo.add(curr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
addTag(curr, tags, toAddTags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean containsAll(String str, String... strings)
|
||||||
|
{
|
||||||
|
return StringHelper.matchesWildcards(str, strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addForbiddenTiles(String toAdd)
|
||||||
|
{
|
||||||
|
FORBIDDEN_TILES.add(toAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addForbiddenEntities(String toAdd)
|
||||||
|
{
|
||||||
|
FORBIDDEN_ENTITIES.add(toAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addForbiddenStacking(String toAdd)
|
||||||
|
{
|
||||||
|
FORBIDDEN_STACKING.add(toAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addAllowedTiles(String toAdd)
|
||||||
|
{
|
||||||
|
ALLOWED_TILES.add(toAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addAllowedEntities(String toAdd)
|
||||||
|
{
|
||||||
|
ALLOWED_ENTITIES.add(toAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addAllowedStacking(String toAdd)
|
||||||
|
{
|
||||||
|
ALLOWED_ENTITIES.add(toAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.common.pickupcondition;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.DataResult;
|
||||||
|
import net.minecraft.commands.arguments.blocks.BlockStateParser;
|
||||||
|
import net.minecraft.commands.arguments.blocks.BlockStateParser.BlockResult;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
|
import tschipp.carryon.platform.Services;
|
||||||
|
import tschipp.carryon.utils.StringHelper;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class PickupCondition
|
||||||
|
{
|
||||||
|
public static Codec<PickupCondition> CODEC = Codec.STRING.comapFlatMap(PickupCondition::of, pickupCondition -> pickupCondition.str);
|
||||||
|
|
||||||
|
private String str, cond, match;
|
||||||
|
private boolean wildcards;
|
||||||
|
|
||||||
|
private PickupCondition(String str, String cond, String match)
|
||||||
|
{
|
||||||
|
this.str = str;
|
||||||
|
this.cond = cond;
|
||||||
|
this.match = match;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataResult<PickupCondition> of(String str)
|
||||||
|
{
|
||||||
|
if(!(str.contains("(") && str.endsWith(")")))
|
||||||
|
return DataResult.error(() -> "Error while parsing: "+ str +". Pickup Condition must contain proper brackets.");
|
||||||
|
|
||||||
|
String cond = str.substring(str.indexOf("(") + 1, str.length()-1);
|
||||||
|
|
||||||
|
String match = str.substring(0, str.indexOf("("));
|
||||||
|
|
||||||
|
PickupCondition condition = new PickupCondition(str, cond, match);
|
||||||
|
if(match.contains("*"))
|
||||||
|
condition.wildcards = true;
|
||||||
|
|
||||||
|
return DataResult.success(condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(BlockState state)
|
||||||
|
{
|
||||||
|
if(wildcards)
|
||||||
|
{
|
||||||
|
String name = match.contains("[") ? match.substring(0, match.indexOf("[")) : match;
|
||||||
|
String[] split = name.replace("*", ",").split(",");
|
||||||
|
String stateName = BuiltInRegistries.BLOCK.getKey(state.getBlock()).toString();
|
||||||
|
|
||||||
|
if(StringHelper.matchesWildcards(stateName, split))
|
||||||
|
{
|
||||||
|
if(match.contains("["))
|
||||||
|
{
|
||||||
|
stateName = stateName + match.substring(match.indexOf("["));
|
||||||
|
BlockResult result = parseState(stateName);
|
||||||
|
return matchesProperties(state, result.properties());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BlockResult res = parseState(match);
|
||||||
|
return res.blockState().getBlock() == state.getBlock() && matchesProperties(state, res.properties());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(Entity entity)
|
||||||
|
{
|
||||||
|
String entityName = BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString();
|
||||||
|
if(wildcards)
|
||||||
|
{
|
||||||
|
String[] split = match.replace("*", ",").split(",");
|
||||||
|
return StringHelper.matchesWildcards(entityName, split);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return entityName.equals(match);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCondition()
|
||||||
|
{
|
||||||
|
return cond;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFulfilled(ServerPlayer player)
|
||||||
|
{
|
||||||
|
return Services.GAMESTAGES.hasStage(player, cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockResult parseState(String state)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
BlockResult result = BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK, state, false);
|
||||||
|
return result;
|
||||||
|
} catch (CommandSyntaxException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matchesProperties(BlockState state, Map<Property<?>, Comparable<?>> props)
|
||||||
|
{
|
||||||
|
for(var entry : props.entrySet())
|
||||||
|
{
|
||||||
|
var val = state.getValue(entry.getKey());
|
||||||
|
if(val != entry.getValue())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.common.pickupcondition;
|
||||||
|
|
||||||
|
import com.mojang.serialization.DataResult;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class PickupConditionHandler
|
||||||
|
{
|
||||||
|
private static final List<PickupCondition> BLOCK_CONDITIONS = new ArrayList<>();
|
||||||
|
private static final List<PickupCondition> ENTITY_CONDITIONS = new ArrayList<>();
|
||||||
|
|
||||||
|
public static void initPickupConditions()
|
||||||
|
{
|
||||||
|
BLOCK_CONDITIONS.clear();
|
||||||
|
ENTITY_CONDITIONS.clear();
|
||||||
|
|
||||||
|
for(String cond : Constants.COMMON_CONFIG.customPickupConditions.customPickupConditionsBlocks)
|
||||||
|
{
|
||||||
|
DataResult<PickupCondition> res = PickupCondition.of(cond);
|
||||||
|
if(res.result().isPresent())
|
||||||
|
{
|
||||||
|
PickupCondition pickupCondition = res.result().get();
|
||||||
|
BLOCK_CONDITIONS.add(pickupCondition);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Constants.LOG.debug("Error while parsing Pickup Conditions: " + res.error().get().message());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for(String cond : Constants.COMMON_CONFIG.customPickupConditions.customPickupConditionsEntities)
|
||||||
|
{
|
||||||
|
DataResult<PickupCondition> res = PickupCondition.of(cond);
|
||||||
|
if(res.result().isPresent())
|
||||||
|
{
|
||||||
|
PickupCondition pickupCondition = res.result().get();
|
||||||
|
ENTITY_CONDITIONS.add(pickupCondition);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Constants.LOG.debug("Error while parsing Pickup Conditions: " + res.error().get().message());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<PickupCondition> getPickupCondition(BlockState state)
|
||||||
|
{
|
||||||
|
for(PickupCondition cond : BLOCK_CONDITIONS)
|
||||||
|
{
|
||||||
|
if(cond.matches(state))
|
||||||
|
return Optional.of(cond);
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<PickupCondition> getPickupCondition(Entity entity)
|
||||||
|
{
|
||||||
|
for(PickupCondition cond : ENTITY_CONDITIONS)
|
||||||
|
{
|
||||||
|
if(cond.matches(entity))
|
||||||
|
return Optional.of(cond);
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,205 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.common.scripting;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectBlock;
|
||||||
|
import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectEntity;
|
||||||
|
import tschipp.carryon.common.scripting.Matchables.*;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public record CarryOnScript(
|
||||||
|
long priority,
|
||||||
|
ScriptObject scriptObject,
|
||||||
|
ScriptConditions scriptConditions,
|
||||||
|
ScriptRender scriptRender,
|
||||||
|
ScriptEffects scriptEffects,
|
||||||
|
boolean overrideChecks)
|
||||||
|
{
|
||||||
|
|
||||||
|
public boolean isValid()
|
||||||
|
{
|
||||||
|
return (isBlock() ^ isEntity()) && (scriptConditions != ScriptConditions.EMPTY || scriptRender != ScriptRender.EMPTY || scriptEffects != ScriptEffects.EMPTY || overrideChecks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBlock()
|
||||||
|
{
|
||||||
|
return scriptObject.block() != ScriptObjectBlock.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEntity()
|
||||||
|
{
|
||||||
|
return scriptObject.entity() != ScriptObjectEntity.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Codec<CarryOnScript> CODEC = RecordCodecBuilder.create(instance -> // Given an instance
|
||||||
|
instance.group(
|
||||||
|
Codec.LONG.optionalFieldOf("priority", 0L).forGetter(CarryOnScript::priority),
|
||||||
|
ScriptObject.CODEC.fieldOf("object").forGetter(CarryOnScript::scriptObject),
|
||||||
|
ScriptConditions.CODEC.optionalFieldOf("conditions", ScriptConditions.EMPTY).forGetter(CarryOnScript::scriptConditions),
|
||||||
|
ScriptRender.CODEC.optionalFieldOf("render", ScriptRender.EMPTY).forGetter(CarryOnScript::scriptRender),
|
||||||
|
ScriptEffects.CODEC.optionalFieldOf("effects", ScriptEffects.EMPTY).forGetter(CarryOnScript::scriptEffects),
|
||||||
|
Codec.BOOL.optionalFieldOf("override_checks", false).forGetter(CarryOnScript::overrideChecks)
|
||||||
|
).apply(instance, CarryOnScript::new)
|
||||||
|
);
|
||||||
|
|
||||||
|
public boolean fulfillsConditions(ServerPlayer player)
|
||||||
|
{
|
||||||
|
ScriptConditions cond = this.scriptConditions();
|
||||||
|
|
||||||
|
boolean achievement = cond.conditionAchievement.matches(player);
|
||||||
|
boolean gamemode = cond.conditionGamemode.matches(player.gameMode.getGameModeForPlayer().getId());
|
||||||
|
boolean gamestage = cond.conditionGamestage.matches(player);
|
||||||
|
boolean position = cond.conditionPosition.matches(player);
|
||||||
|
boolean xp = cond.conditionXp.matches(player.experienceLevel);
|
||||||
|
boolean scoreboard = cond.conditionScoreboard.matches(player);
|
||||||
|
boolean effects = cond.conditionEffects.matches(player);
|
||||||
|
|
||||||
|
return achievement && gamemode && gamestage && position && xp && scoreboard && effects;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public record ScriptObject(ScriptObjectBlock block, ScriptObjectEntity entity)
|
||||||
|
{
|
||||||
|
public static final Codec<ScriptObject> CODEC = RecordCodecBuilder.create(instance ->
|
||||||
|
instance.group(
|
||||||
|
ScriptObjectBlock.CODEC.optionalFieldOf("block", ScriptObjectBlock.EMPTY).forGetter(ScriptObject::block),
|
||||||
|
ScriptObjectEntity.CODEC.optionalFieldOf("entity", ScriptObjectEntity.EMPTY).forGetter(ScriptObject::entity)
|
||||||
|
).apply(instance, ScriptObject::new)
|
||||||
|
);
|
||||||
|
|
||||||
|
public record ScriptObjectBlock(
|
||||||
|
Optional<ResourceKey<Block>> typeNameBlock,
|
||||||
|
NumberBoundCondition typeHardness,
|
||||||
|
NumberBoundCondition typeResistance,
|
||||||
|
NBTCondition typeBlockTag
|
||||||
|
){
|
||||||
|
public static final ScriptObjectBlock EMPTY = new ScriptObjectBlock(Optional.empty(), NumberBoundCondition.NONE, NumberBoundCondition.NONE, NBTCondition.NONE);
|
||||||
|
|
||||||
|
public static final Codec<ScriptObjectBlock> CODEC = RecordCodecBuilder.create(instance ->
|
||||||
|
instance.group(
|
||||||
|
ResourceKey.codec(Registries.BLOCK).optionalFieldOf("name").forGetter(ScriptObjectBlock::typeNameBlock),
|
||||||
|
NumberBoundCondition.CODEC.optionalFieldOf("hardness", NumberBoundCondition.NONE).forGetter(ScriptObjectBlock::typeHardness),
|
||||||
|
NumberBoundCondition.CODEC.optionalFieldOf("resistance", NumberBoundCondition.NONE).forGetter(ScriptObjectBlock::typeResistance),
|
||||||
|
NBTCondition.CODEC.optionalFieldOf("nbt", NBTCondition.NONE).forGetter(ScriptObjectBlock::typeBlockTag)
|
||||||
|
).apply(instance, ScriptObjectBlock::new)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record ScriptObjectEntity(
|
||||||
|
Optional<ResourceKey<EntityType<?>>> typeNameEntity,
|
||||||
|
NumberBoundCondition typeHealth,
|
||||||
|
NumberBoundCondition typeHeight,
|
||||||
|
NumberBoundCondition typeWidth,
|
||||||
|
NBTCondition typeEntityTag
|
||||||
|
){
|
||||||
|
public static final ScriptObjectEntity EMPTY = new ScriptObjectEntity(Optional.empty(), NumberBoundCondition.NONE, NumberBoundCondition.NONE, NumberBoundCondition.NONE, NBTCondition.NONE);
|
||||||
|
|
||||||
|
public static final Codec<ScriptObjectEntity> CODEC = RecordCodecBuilder.create(instance ->
|
||||||
|
instance.group(
|
||||||
|
ResourceKey.codec(Registries.ENTITY_TYPE).optionalFieldOf("name").forGetter(ScriptObjectEntity::typeNameEntity),
|
||||||
|
NumberBoundCondition.CODEC.optionalFieldOf("health", NumberBoundCondition.NONE).forGetter(ScriptObjectEntity::typeHealth),
|
||||||
|
NumberBoundCondition.CODEC.optionalFieldOf("height", NumberBoundCondition.NONE).forGetter(ScriptObjectEntity::typeHeight),
|
||||||
|
NumberBoundCondition.CODEC.optionalFieldOf("width", NumberBoundCondition.NONE).forGetter(ScriptObjectEntity::typeWidth),
|
||||||
|
NBTCondition.CODEC.optionalFieldOf("nbt", NBTCondition.NONE).forGetter(ScriptObjectEntity::typeEntityTag)
|
||||||
|
).apply(instance, ScriptObjectEntity::new)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record ScriptConditions(
|
||||||
|
GamestageCondition conditionGamestage,
|
||||||
|
AdvancementCondition conditionAchievement,
|
||||||
|
NumberBoundCondition conditionXp,
|
||||||
|
NumberBoundCondition conditionGamemode,
|
||||||
|
ScoreboardCondition conditionScoreboard,
|
||||||
|
PositionCondition conditionPosition,
|
||||||
|
EffectsCondition conditionEffects
|
||||||
|
){
|
||||||
|
public static final ScriptConditions EMPTY = new ScriptConditions(GamestageCondition.NONE, AdvancementCondition.NONE, NumberBoundCondition.NONE, NumberBoundCondition.NONE, ScoreboardCondition.NONE, PositionCondition.NONE, EffectsCondition.NONE);
|
||||||
|
|
||||||
|
public static final Codec<ScriptConditions> CODEC = RecordCodecBuilder.create(instance ->
|
||||||
|
instance.group(
|
||||||
|
GamestageCondition.CODEC.optionalFieldOf("gamestage", GamestageCondition.NONE).forGetter(ScriptConditions::conditionGamestage),
|
||||||
|
AdvancementCondition.CODEC.optionalFieldOf("advancement", AdvancementCondition.NONE).forGetter(ScriptConditions::conditionAchievement),
|
||||||
|
NumberBoundCondition.CODEC.optionalFieldOf("xp", NumberBoundCondition.NONE).forGetter(ScriptConditions::conditionXp),
|
||||||
|
NumberBoundCondition.CODEC.optionalFieldOf("gamemode", NumberBoundCondition.NONE).forGetter(ScriptConditions::conditionGamemode),
|
||||||
|
ScoreboardCondition.CODEC.optionalFieldOf("scoreboard", ScoreboardCondition.NONE).forGetter(ScriptConditions::conditionScoreboard),
|
||||||
|
PositionCondition.CODEC.optionalFieldOf("position", PositionCondition.NONE).forGetter(ScriptConditions::conditionPosition),
|
||||||
|
EffectsCondition.CODEC.optionalFieldOf("effects", EffectsCondition.NONE).forGetter(ScriptConditions::conditionEffects)
|
||||||
|
).apply(instance, ScriptConditions::new)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record ScriptRender(
|
||||||
|
Optional<ResourceKey<Block>> renderNameBlock,
|
||||||
|
Optional<ResourceKey<EntityType<?>>> renderNameEntity,
|
||||||
|
Optional<CompoundTag> renderNBT,
|
||||||
|
OptionalVec3 renderTranslation,
|
||||||
|
OptionalVec3 renderRotation,
|
||||||
|
OptionalVec3 renderscale,
|
||||||
|
OptionalVec3 renderRotationLeftArm,
|
||||||
|
OptionalVec3 renderRotationRightArm,
|
||||||
|
boolean renderLeftArm,
|
||||||
|
boolean renderRightArm
|
||||||
|
){
|
||||||
|
public static final ScriptRender EMPTY = new ScriptRender(Optional.empty(), Optional.empty(), Optional.empty(), OptionalVec3.NONE, OptionalVec3.NONE, OptionalVec3.NONE, OptionalVec3.NONE, OptionalVec3.NONE, true, true);
|
||||||
|
|
||||||
|
public static final Codec<ScriptRender> CODEC = RecordCodecBuilder.create(instance ->
|
||||||
|
instance.group(
|
||||||
|
ResourceKey.codec(Registries.BLOCK).optionalFieldOf("name_block").forGetter(ScriptRender::renderNameBlock),
|
||||||
|
ResourceKey.codec(Registries.ENTITY_TYPE).optionalFieldOf("name_entity").forGetter(ScriptRender::renderNameEntity),
|
||||||
|
CompoundTag.CODEC.optionalFieldOf("nbt").forGetter(ScriptRender::renderNBT),
|
||||||
|
OptionalVec3.CODEC.optionalFieldOf("translation", OptionalVec3.NONE).forGetter(ScriptRender::renderTranslation),
|
||||||
|
OptionalVec3.CODEC.optionalFieldOf("rotation", OptionalVec3.NONE).forGetter(ScriptRender::renderRotation),
|
||||||
|
OptionalVec3.CODEC.optionalFieldOf("scale", OptionalVec3.NONE).forGetter(ScriptRender::renderscale),
|
||||||
|
OptionalVec3.CODEC.optionalFieldOf("rotation_left_arm", OptionalVec3.NONE).forGetter(ScriptRender::renderRotationLeftArm),
|
||||||
|
OptionalVec3.CODEC.optionalFieldOf("rotation_right_arm", OptionalVec3.NONE).forGetter(ScriptRender::renderRotationRightArm),
|
||||||
|
Codec.BOOL.optionalFieldOf("render_left_arm", true).forGetter(ScriptRender::renderLeftArm),
|
||||||
|
Codec.BOOL.optionalFieldOf("render_right_arm", true).forGetter(ScriptRender::renderRightArm)
|
||||||
|
).apply(instance, ScriptRender::new)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record ScriptEffects(
|
||||||
|
String commandInit,
|
||||||
|
String commandLoop,
|
||||||
|
String commandPlace
|
||||||
|
){
|
||||||
|
public static final ScriptEffects EMPTY = new ScriptEffects("", "", "");
|
||||||
|
|
||||||
|
public static final Codec<ScriptEffects> CODEC = RecordCodecBuilder.create(instance ->
|
||||||
|
instance.group(
|
||||||
|
Codec.STRING.optionalFieldOf("commandPickup", "").forGetter(ScriptEffects::commandInit),
|
||||||
|
Codec.STRING.optionalFieldOf("commandLoop", "").forGetter(ScriptEffects::commandLoop),
|
||||||
|
Codec.STRING.optionalFieldOf("commandPlace", "").forGetter(ScriptEffects::commandPlace)
|
||||||
|
).apply(instance, ScriptEffects::new)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,354 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.common.scripting;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
|
import net.minecraft.advancements.AdvancementHolder;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.NbtUtils;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
import net.minecraft.server.ServerAdvancementManager;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.scores.Objective;
|
||||||
|
import net.minecraft.world.scores.Scoreboard;
|
||||||
|
import tschipp.carryon.platform.Services;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public final class Matchables
|
||||||
|
{
|
||||||
|
public interface Matchable<T>
|
||||||
|
{
|
||||||
|
boolean matches(T elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float getValueFromStringOrDefault(String toGetFrom, String key, float defaultVal)
|
||||||
|
{
|
||||||
|
Optional<Float> val = getValueFromString(toGetFrom, key);
|
||||||
|
return val.orElse(defaultVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<Float> getValueFromString(String toGetFrom, String key)
|
||||||
|
{
|
||||||
|
if (toGetFrom == null || toGetFrom.isEmpty())
|
||||||
|
return Optional.empty();
|
||||||
|
|
||||||
|
String[] s = toGetFrom.split(",");
|
||||||
|
for (String string : s)
|
||||||
|
{
|
||||||
|
if (string.contains(key) && string.contains("="))
|
||||||
|
{
|
||||||
|
float numb = 0;
|
||||||
|
string = string.replace(key + "=", "");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
numb = Float.parseFloat(string);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.of(numb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public record NumberBoundCondition(String bounds) implements Matchable<Number>
|
||||||
|
{
|
||||||
|
public static final Codec<NumberBoundCondition> CODEC = Codec.STRING.xmap(NumberBoundCondition::new, NumberBoundCondition::bounds);
|
||||||
|
|
||||||
|
public static final NumberBoundCondition NONE = new NumberBoundCondition("");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Number num)
|
||||||
|
{
|
||||||
|
double number = num.doubleValue();
|
||||||
|
|
||||||
|
if (bounds == null || bounds.isEmpty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (bounds.contains("<="))
|
||||||
|
return number <= Double.parseDouble(bounds.replace("<=", ""));
|
||||||
|
if (bounds.contains(">="))
|
||||||
|
return number >= Double.parseDouble(bounds.replace(">=", ""));
|
||||||
|
if (bounds.contains("<"))
|
||||||
|
return number < Double.parseDouble(bounds.replace("<", ""));
|
||||||
|
if (bounds.contains(">"))
|
||||||
|
return number > Double.parseDouble(bounds.replace(">", ""));
|
||||||
|
if (bounds.contains("="))
|
||||||
|
return number == Double.parseDouble(bounds.replace("=", ""));
|
||||||
|
else
|
||||||
|
return number == Double.parseDouble(bounds);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Error while parsing Number bound for string: "+ bounds + ". Error: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record AdvancementCondition(String advancement) implements Matchable<ServerPlayer>
|
||||||
|
{
|
||||||
|
public static final Codec<AdvancementCondition> CODEC = Codec.STRING.xmap(AdvancementCondition::new, AdvancementCondition::advancement);
|
||||||
|
|
||||||
|
public static final AdvancementCondition NONE = new AdvancementCondition("");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(ServerPlayer player)
|
||||||
|
{
|
||||||
|
ServerAdvancementManager manager = player.level().getServer().getAdvancements();
|
||||||
|
AdvancementHolder adv = manager.get(Identifier.parse(advancement.isEmpty() ? "" : advancement));
|
||||||
|
|
||||||
|
boolean achievement = adv == null ? true : player.getAdvancements().getOrStartProgress(adv).isDone();
|
||||||
|
return achievement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record GamestageCondition(String gamestage) implements Matchable<ServerPlayer>
|
||||||
|
{
|
||||||
|
public static final Codec<GamestageCondition> CODEC = Codec.STRING.xmap(GamestageCondition::new, GamestageCondition::gamestage);
|
||||||
|
|
||||||
|
public static final GamestageCondition NONE = new GamestageCondition("");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(ServerPlayer player)
|
||||||
|
{
|
||||||
|
if(!Services.PLATFORM.isModLoaded("gamestages"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(gamestage == null || gamestage.isEmpty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return Services.GAMESTAGES.hasStage(player, gamestage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record ScoreboardCondition(String cond) implements Matchable<ServerPlayer>
|
||||||
|
{
|
||||||
|
public static final Codec<ScoreboardCondition> CODEC = Codec.STRING.xmap(ScoreboardCondition::new, ScoreboardCondition::cond);
|
||||||
|
|
||||||
|
public static final ScoreboardCondition NONE = new ScoreboardCondition("");
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(ServerPlayer player)
|
||||||
|
{
|
||||||
|
if (cond == null || cond.isEmpty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Scoreboard score = player.level().getScoreboard();
|
||||||
|
String numb;
|
||||||
|
String scorename;
|
||||||
|
int iE = cond.indexOf("=");
|
||||||
|
int iG = cond.indexOf(">");
|
||||||
|
int iL = cond.indexOf("<");
|
||||||
|
|
||||||
|
if (iG == -1 || (iE < iG && iL == -1 || iE < iL && iE != -1))
|
||||||
|
numb = cond.substring(iE);
|
||||||
|
else if (iE == -1 || (iG < iE && iL == -1 || iG < iL && iG != -1))
|
||||||
|
numb = cond.substring(iG);
|
||||||
|
else
|
||||||
|
numb = cond.substring(iL);
|
||||||
|
|
||||||
|
scorename = cond.replace(numb, "");
|
||||||
|
Object2IntMap<Objective> scores = score.listPlayerScores(player);
|
||||||
|
int scoreVal = scores.getInt(score.getObjective(scorename));
|
||||||
|
|
||||||
|
return new NumberBoundCondition(numb).matches(scoreVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record PositionCondition(String cond) implements Matchable<ServerPlayer>
|
||||||
|
{
|
||||||
|
public static final Codec<PositionCondition> CODEC = Codec.STRING.xmap(PositionCondition::new, PositionCondition::cond);
|
||||||
|
|
||||||
|
public static final PositionCondition NONE = new PositionCondition("");
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(ServerPlayer elem)
|
||||||
|
{
|
||||||
|
if (cond == null || cond.isEmpty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
BlockPos blockpos = new BlockPos((int) getValueFromStringOrDefault(cond, "x", 0), (int) getValueFromStringOrDefault(cond, "y", 0), (int) getValueFromStringOrDefault(cond, "z", 0));
|
||||||
|
BlockPos expand = new BlockPos((int) getValueFromStringOrDefault(cond, "dx", 0), (int) getValueFromStringOrDefault(cond, "dy", 0), (int) getValueFromStringOrDefault(cond, "dz", 0));
|
||||||
|
BlockPos expanded = blockpos.offset(expand);
|
||||||
|
BlockPos pos = elem.blockPosition();
|
||||||
|
|
||||||
|
boolean x = pos.getX() >= blockpos.getX() && pos.getX() <= expanded.getX() || blockpos.getX() == 0;
|
||||||
|
boolean y = pos.getY() >= blockpos.getY() && pos.getY() <= expanded.getY() || blockpos.getY() == 0;
|
||||||
|
boolean z = pos.getZ() >= blockpos.getZ() && pos.getZ() <= expanded.getZ() || blockpos.getZ() == 0;
|
||||||
|
|
||||||
|
return x && y && z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record EffectsCondition(String effects) implements Matchable<ServerPlayer>
|
||||||
|
{
|
||||||
|
public static final Codec<EffectsCondition> CODEC = Codec.STRING.xmap(EffectsCondition::new, EffectsCondition::effects);
|
||||||
|
|
||||||
|
public static final EffectsCondition NONE = new EffectsCondition("");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(ServerPlayer player)
|
||||||
|
{
|
||||||
|
if (effects == null || effects.isEmpty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Collection<MobEffectInstance> fx = player.getActiveEffects();
|
||||||
|
String[] potions = effects.split(",");
|
||||||
|
|
||||||
|
List<String> names = new ArrayList<>();
|
||||||
|
List<Integer> levels = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String pot : potions)
|
||||||
|
{
|
||||||
|
if (pot.contains("#"))
|
||||||
|
{
|
||||||
|
String level = pot.substring(pot.indexOf("#"));
|
||||||
|
String name = pot.substring(0, pot.indexOf("#"));
|
||||||
|
level = level.replace("#", "");
|
||||||
|
int lev = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lev = Integer.parseInt(level);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
levels.add(lev);
|
||||||
|
names.add(name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
levels.add(0);
|
||||||
|
names.add(pot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int matches = 0;
|
||||||
|
for (MobEffectInstance effect : fx)
|
||||||
|
{
|
||||||
|
int amp = effect.getAmplifier();
|
||||||
|
String name = effect.getEffect().getRegisteredName();
|
||||||
|
|
||||||
|
if (names.contains(name))
|
||||||
|
{
|
||||||
|
int idx = names.indexOf(name);
|
||||||
|
int lev = levels.get(idx);
|
||||||
|
|
||||||
|
if (lev <= amp)
|
||||||
|
matches++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches == potions.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record NBTCondition(CompoundTag tag) implements Matchable<CompoundTag>
|
||||||
|
{
|
||||||
|
public static final Codec<NBTCondition> CODEC = CompoundTag.CODEC.xmap(NBTCondition::new, NBTCondition::tag);
|
||||||
|
|
||||||
|
public static final NBTCondition NONE = new NBTCondition(new CompoundTag());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(CompoundTag other)
|
||||||
|
{
|
||||||
|
if(other == null)
|
||||||
|
return true;
|
||||||
|
return NbtUtils.compareNbt(tag, other, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class OptionalVec3 {
|
||||||
|
|
||||||
|
public static final Codec<OptionalVec3> CODEC = Codec.STRING.xmap(OptionalVec3::new, OptionalVec3::source);
|
||||||
|
|
||||||
|
public static final OptionalVec3 NONE = new OptionalVec3("");
|
||||||
|
|
||||||
|
String source;
|
||||||
|
Vec3 vec;
|
||||||
|
|
||||||
|
boolean x, y, z;
|
||||||
|
|
||||||
|
public OptionalVec3(String source)
|
||||||
|
{
|
||||||
|
this.source = source;
|
||||||
|
Optional<Float> xOpt = getValueFromString(source, "x");
|
||||||
|
Optional<Float> yOpt = getValueFromString(source, "y");
|
||||||
|
Optional<Float> zOpt = getValueFromString(source, "z");
|
||||||
|
|
||||||
|
float x = 0, y = 0, z = 0;
|
||||||
|
|
||||||
|
if(xOpt.isPresent()) {
|
||||||
|
x = xOpt.get();
|
||||||
|
this.x = true;
|
||||||
|
}
|
||||||
|
if(yOpt.isPresent()) {
|
||||||
|
y = yOpt.get();
|
||||||
|
this.y = true;
|
||||||
|
}
|
||||||
|
if(zOpt.isPresent()) {
|
||||||
|
z = zOpt.get();
|
||||||
|
this.z = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec = new Vec3(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String source()
|
||||||
|
{
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the contained optional vector. Nonexisting numbers are set to 0.
|
||||||
|
*/
|
||||||
|
public Vec3 getVec()
|
||||||
|
{
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 getVec(double dX, double dY, double dZ)
|
||||||
|
{
|
||||||
|
double x = !this.x ? dX : vec.x;
|
||||||
|
double y = !this.y ? dY : vec.y;
|
||||||
|
double z = !this.z ? dZ : vec.z;
|
||||||
|
return new Vec3(x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.common.scripting;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.util.ProblemReporter;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.storage.TagValueOutput;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectBlock;
|
||||||
|
import tschipp.carryon.common.scripting.CarryOnScript.ScriptObject.ScriptObjectEntity;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class ScriptManager
|
||||||
|
{
|
||||||
|
public static final List<CarryOnScript> SCRIPTS = new ArrayList<>();
|
||||||
|
|
||||||
|
public static Optional<CarryOnScript> inspectBlock(BlockState state, Level level, BlockPos pos, @Nullable CompoundTag tag)
|
||||||
|
{
|
||||||
|
if (!Constants.COMMON_CONFIG.settings.useScripts)
|
||||||
|
return Optional.empty();
|
||||||
|
|
||||||
|
Block block = state.getBlock();
|
||||||
|
float hardness = state.getDestroySpeed(level, pos);
|
||||||
|
float resistance = block.getExplosionResistance();
|
||||||
|
|
||||||
|
for (CarryOnScript script : SCRIPTS)
|
||||||
|
{
|
||||||
|
if (script.isBlock() && matchesAll(script, block, hardness, resistance, tag))
|
||||||
|
return Optional.of(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<CarryOnScript> inspectEntity(Entity entity)
|
||||||
|
{
|
||||||
|
if (!Constants.COMMON_CONFIG.settings.useScripts)
|
||||||
|
return Optional.empty();
|
||||||
|
|
||||||
|
float height = entity.getBbHeight();
|
||||||
|
float width = entity.getBbWidth();
|
||||||
|
float health = entity instanceof LivingEntity ? ((LivingEntity) entity).getHealth() : 0.0f;
|
||||||
|
TagValueOutput output = TagValueOutput.createWithContext(new ProblemReporter.ScopedCollector(Constants.LOG), entity.registryAccess());
|
||||||
|
entity.save(output);
|
||||||
|
CompoundTag tag = output.buildResult();
|
||||||
|
|
||||||
|
for (CarryOnScript script : SCRIPTS)
|
||||||
|
{
|
||||||
|
if (script.isEntity() && matchesAll(script, entity, height, width, health, tag))
|
||||||
|
return Optional.of(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean matchesAll(CarryOnScript script, Entity entity, float height, float width, float health, CompoundTag tag)
|
||||||
|
{
|
||||||
|
ScriptObjectEntity scEntity = script.scriptObject().entity();
|
||||||
|
|
||||||
|
boolean matchname = true;
|
||||||
|
if(scEntity.typeNameEntity().isPresent())
|
||||||
|
matchname = entity.getType().equals(BuiltInRegistries.ENTITY_TYPE.get(scEntity.typeNameEntity().get()));
|
||||||
|
boolean matchheight = scEntity.typeHeight().matches(height);
|
||||||
|
boolean matchwidth = scEntity.typeWidth().matches(width);
|
||||||
|
boolean matchhealth = scEntity.typeHealth().matches(health);
|
||||||
|
boolean matchnbt = scEntity.typeEntityTag().matches(tag);
|
||||||
|
|
||||||
|
return matchname && matchheight && matchwidth && matchhealth && matchnbt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean matchesAll(CarryOnScript script, Block block, float hardness, float resistance, CompoundTag nbt)
|
||||||
|
{
|
||||||
|
ScriptObjectBlock scBlock = script.scriptObject().block();
|
||||||
|
|
||||||
|
boolean matchblock = true;
|
||||||
|
if(scBlock.typeNameBlock().isPresent())
|
||||||
|
matchblock = block == BuiltInRegistries.BLOCK.get(scBlock.typeNameBlock().get()).get().value();
|
||||||
|
boolean matchnbt = scBlock.typeBlockTag().matches(nbt);
|
||||||
|
boolean matchhardness = scBlock.typeHardness().matches(hardness);
|
||||||
|
boolean matchresistance = scBlock.typeResistance().matches(resistance);
|
||||||
|
|
||||||
|
return matchnbt && matchblock && matchhardness && matchresistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.common.scripting;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.DataResult;
|
||||||
|
import net.minecraft.nbt.NbtOps;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.resources.FileToIdConverter;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.packs.resources.ResourceManager;
|
||||||
|
import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
|
||||||
|
import net.minecraft.util.profiling.ProfilerFiller;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.networking.clientbound.ClientboundSyncScriptsPacket;
|
||||||
|
import tschipp.carryon.platform.Services;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ScriptReloadListener extends SimpleJsonResourceReloadListener<CarryOnScript>
|
||||||
|
{
|
||||||
|
public ScriptReloadListener()
|
||||||
|
{
|
||||||
|
super(CarryOnScript.CODEC, FileToIdConverter.json("carryon/scripts"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void apply(Map<Identifier, CarryOnScript> scripts, @NotNull ResourceManager resourceManager, @NotNull ProfilerFiller profilerFiller)
|
||||||
|
{
|
||||||
|
ScriptManager.SCRIPTS.clear();
|
||||||
|
|
||||||
|
scripts.forEach((path, script) -> {
|
||||||
|
if (script.isValid())
|
||||||
|
ScriptManager.SCRIPTS.add(script);
|
||||||
|
});
|
||||||
|
|
||||||
|
ScriptManager.SCRIPTS.sort((s1, s2) -> Long.compare(s2.priority(), s1.priority()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void syncScriptsWithClient(ServerPlayer player)
|
||||||
|
{
|
||||||
|
if (player != null)
|
||||||
|
{
|
||||||
|
DataResult<Tag> result = Codec.list(CarryOnScript.CODEC).encodeStart(NbtOps.INSTANCE, ScriptManager.SCRIPTS);
|
||||||
|
Tag tag = result.getOrThrow(s -> {throw new RuntimeException("Error while synching Carry On Scripts: " + s);});
|
||||||
|
|
||||||
|
Services.PLATFORM.sendPacketToPlayer(Constants.PACKET_ID_SYNC_SCRIPTS, new ClientboundSyncScriptsPacket(tag), player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.config;
|
||||||
|
|
||||||
|
|
||||||
|
import tschipp.carryon.config.annotations.Property;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
public record AnnotationData(
|
||||||
|
PropertyType type,
|
||||||
|
String description,
|
||||||
|
int min, int max,
|
||||||
|
double minD, double maxD,
|
||||||
|
String validationRegex
|
||||||
|
) {
|
||||||
|
|
||||||
|
public static AnnotationData getData(Field field) {
|
||||||
|
Property annotation = field.getAnnotation(Property.class);
|
||||||
|
return new AnnotationData(
|
||||||
|
annotation.type(),
|
||||||
|
annotation.description(),
|
||||||
|
annotation.min(), annotation.max(),
|
||||||
|
annotation.minD(), annotation.maxD(),
|
||||||
|
annotation.validationRegex()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.config;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class BuiltCategory {
|
||||||
|
|
||||||
|
public final List<PropertyData> properties = new ArrayList<>();
|
||||||
|
public final List<BuiltCategory> categories = new ArrayList<>();
|
||||||
|
|
||||||
|
public final String categoryDesc;
|
||||||
|
public final String category;
|
||||||
|
|
||||||
|
public final String translation;
|
||||||
|
|
||||||
|
public BuiltCategory(String categoryDesc, String category, String translation) {
|
||||||
|
this.categoryDesc = categoryDesc;
|
||||||
|
this.category = category;
|
||||||
|
this.translation = translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<PropertyData> getProperty(String id) {
|
||||||
|
for (PropertyData property : properties) {
|
||||||
|
if (property.getId().equals(id)) {
|
||||||
|
return Optional.of(property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<BuiltCategory> getCategory(String id) {
|
||||||
|
for (BuiltCategory category : categories) {
|
||||||
|
if (category.category.equals(id)) {
|
||||||
|
return Optional.of(category);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
31
Common/src/main/java/tschipp/carryon/config/BuiltConfig.java
Normal file
31
Common/src/main/java/tschipp/carryon/config/BuiltConfig.java
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.config;
|
||||||
|
|
||||||
|
public class BuiltConfig extends BuiltCategory {
|
||||||
|
|
||||||
|
public final String fileName;
|
||||||
|
|
||||||
|
public BuiltConfig(String fileName) {
|
||||||
|
super(null, fileName, "key.carry.category");
|
||||||
|
this.fileName = fileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.config;
|
||||||
|
|
||||||
|
//Many Thanks to ThatGravyBoat for this template!
|
||||||
|
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
|
import tschipp.carryon.client.modeloverride.ModelOverrideHandler;
|
||||||
|
import tschipp.carryon.common.config.ListHandler;
|
||||||
|
import tschipp.carryon.common.pickupcondition.PickupConditionHandler;
|
||||||
|
import tschipp.carryon.config.annotations.Category;
|
||||||
|
import tschipp.carryon.config.annotations.Config;
|
||||||
|
import tschipp.carryon.config.annotations.Property;
|
||||||
|
import tschipp.carryon.platform.Services;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
public class ConfigLoader {
|
||||||
|
|
||||||
|
public static void registerConfig(Object object) {
|
||||||
|
BuiltCategory category;
|
||||||
|
try {
|
||||||
|
category = buildCategory(null, object);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
category = null;
|
||||||
|
}
|
||||||
|
if (category instanceof BuiltConfig config) {
|
||||||
|
registerConfig(config);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Config supplied does not have a @Config annotation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerConfig(BuiltConfig config) {
|
||||||
|
Services.PLATFORM.registerConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onConfigLoaded(HolderLookup.Provider provider) {
|
||||||
|
ListHandler.initConfigLists();
|
||||||
|
PickupConditionHandler.initPickupConditions();
|
||||||
|
ModelOverrideHandler.initModelOverrides(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BuiltCategory buildCategory(String categoryDesc, Object object) throws IllegalAccessException {
|
||||||
|
Class<?> configClass = object.getClass();
|
||||||
|
BuiltCategory category;
|
||||||
|
if (configClass.isAnnotationPresent(Config.class)) {
|
||||||
|
category = new BuiltConfig(configClass.getAnnotation(Config.class).value());
|
||||||
|
} else if (configClass.isAnnotationPresent(Category.class)) {
|
||||||
|
category = new BuiltCategory(categoryDesc, configClass.getAnnotation(Category.class).value(), configClass.getAnnotation(Category.class).translation());
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Config does not contain any @Config annotation or @Category");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Field field : configClass.getDeclaredFields()) {
|
||||||
|
if (field.isAnnotationPresent(Property.class) && field.canAccess(object)) {
|
||||||
|
PropertyType type = field.getAnnotation(Property.class).type();
|
||||||
|
if (type.equals(PropertyType.CATEGORY)) {
|
||||||
|
category.categories.add(buildCategory(field.getAnnotation(Property.class).description(), field.get(object)));
|
||||||
|
} else {
|
||||||
|
category.properties.add(new PropertyData(object, field, AnnotationData.getData(field), field.get(object)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
}
|
||||||
129
Common/src/main/java/tschipp/carryon/config/PropertyData.java
Normal file
129
Common/src/main/java/tschipp/carryon/config/PropertyData.java
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.config;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class PropertyData {
|
||||||
|
|
||||||
|
Object fieldClass;
|
||||||
|
Field field;
|
||||||
|
AnnotationData data;
|
||||||
|
Object defaultValue;
|
||||||
|
Consumer<?> setter;
|
||||||
|
|
||||||
|
public PropertyData(Object fieldClass, Field field, AnnotationData data, Object defaultValue) {
|
||||||
|
this.fieldClass = fieldClass;
|
||||||
|
this.field = field;
|
||||||
|
this.data = data;
|
||||||
|
this.defaultValue = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer<?> getSetter() {
|
||||||
|
return setter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSetter(Consumer<?> setter) {
|
||||||
|
this.setter = setter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnnotationData getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Field getField() {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getFieldClass() {
|
||||||
|
return fieldClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return field.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getBoolean() throws IllegalAccessException {
|
||||||
|
return field.getBoolean(fieldClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBoolean(boolean _boolean) {
|
||||||
|
try {
|
||||||
|
field.setBoolean(fieldClass, _boolean);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getDefaultBoolean() {
|
||||||
|
return (boolean)defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInt() throws IllegalAccessException {
|
||||||
|
return field.getInt(fieldClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInt(int _int) {
|
||||||
|
try {
|
||||||
|
field.setInt(fieldClass, _int);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDefaultInt() {
|
||||||
|
return (int)defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDouble() throws IllegalAccessException {
|
||||||
|
return field.getDouble(fieldClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDouble(double _double) {
|
||||||
|
try {
|
||||||
|
field.setDouble(fieldClass, _double);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDefaultDouble() {
|
||||||
|
return (double)defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getStringArray() throws IllegalAccessException {
|
||||||
|
return (String[])field.get(fieldClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStringArray(String[] arr)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
field.set(fieldClass, arr);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getDefaultStringArray() {
|
||||||
|
return (String[])defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.config;
|
||||||
|
|
||||||
|
public enum PropertyType {
|
||||||
|
INT,
|
||||||
|
DOUBLE,
|
||||||
|
BOOLEAN,
|
||||||
|
STRING_ARRAY,
|
||||||
|
CATEGORY
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.config.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Category {
|
||||||
|
String value();
|
||||||
|
String translation() default "";
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.config.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Config {
|
||||||
|
String value();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.config.annotations;
|
||||||
|
|
||||||
|
import tschipp.carryon.config.PropertyType;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target({ElementType.FIELD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Property {
|
||||||
|
|
||||||
|
|
||||||
|
PropertyType type();
|
||||||
|
String description();
|
||||||
|
|
||||||
|
int min() default Integer.MIN_VALUE;
|
||||||
|
int max() default Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
double minD() default Double.MIN_VALUE;
|
||||||
|
double maxD() default Double.MAX_VALUE;
|
||||||
|
|
||||||
|
String validationRegex() default ".*";
|
||||||
|
}
|
||||||
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
115
Common/src/main/java/tschipp/carryon/mixin/EntityMixin.java
Normal file
115
Common/src/main/java/tschipp/carryon/mixin/EntityMixin.java
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.mixin;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.Entity.MoveFunction;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData.CarryType;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnDataManager;
|
||||||
|
import tschipp.carryon.networking.clientbound.ClientboundStartRidingPacket;
|
||||||
|
import tschipp.carryon.platform.Services;
|
||||||
|
|
||||||
|
@Mixin(Entity.class)
|
||||||
|
public abstract class EntityMixin
|
||||||
|
{
|
||||||
|
@Shadow
|
||||||
|
public boolean hasPassenger(Entity pEntity) {throw new IllegalStateException("EntityMixin application failed");}
|
||||||
|
|
||||||
|
|
||||||
|
@ModifyExpressionValue(method = "startRiding(Lnet/minecraft/world/entity/Entity;ZZ)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/EntityType;canSerialize()Z"))
|
||||||
|
private boolean onStartRidingCheck(boolean original, Entity entity, boolean force) {
|
||||||
|
if (force && entity instanceof Player) return true;
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Shadow public abstract void onPassengerTurned(Entity $$0);
|
||||||
|
|
||||||
|
@Inject(method = "positionRider(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/entity/Entity$MoveFunction;)V", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void onPositionPassenger(Entity entity, MoveFunction move, CallbackInfo ci)
|
||||||
|
{
|
||||||
|
if((Object)this instanceof Player thisPlayer && entity instanceof Player otherPlayer)
|
||||||
|
{
|
||||||
|
if(hasPassenger(otherPlayer) && CarryOnDataManager.getCarryData(thisPlayer).isCarrying(CarryType.PLAYER))
|
||||||
|
{
|
||||||
|
Vec3 forward = new Vec3(0, 0, 0.6);
|
||||||
|
Vec3 otherPos = thisPlayer.position().add(forward.yRot((float) Math.toRadians(-thisPlayer.yBodyRot)));
|
||||||
|
otherPos = otherPos.add(0, 0.4,0);
|
||||||
|
move.accept(otherPlayer, otherPos.x, otherPos.y, otherPos.z);
|
||||||
|
((Entity)((Object)this)).onPassengerTurned(otherPlayer);
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "getDismountLocationForPassenger(Lnet/minecraft/world/entity/LivingEntity;)Lnet/minecraft/world/phys/Vec3;", at = @At("HEAD"))
|
||||||
|
private void onDismountPassenger(LivingEntity living, CallbackInfoReturnable<Vec3> cir)
|
||||||
|
{
|
||||||
|
if((Object)this instanceof Player thisPlayer && living instanceof Player otherPlayer)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(thisPlayer);
|
||||||
|
if(carry.isCarrying(CarryType.PLAYER))
|
||||||
|
{
|
||||||
|
carry.clear();
|
||||||
|
CarryOnDataManager.setCarryData(thisPlayer, carry);
|
||||||
|
Services.PLATFORM.sendPacketToPlayer(Constants.PACKET_ID_START_RIDING, new ClientboundStartRidingPacket(otherPlayer.getId(), false), (ServerPlayer) thisPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "onPassengerTurned(Lnet/minecraft/world/entity/Entity;)V", at = @At("HEAD"))
|
||||||
|
private void onPassengerTurned(Entity toUpdate, CallbackInfo ci)
|
||||||
|
{
|
||||||
|
if((Object)this instanceof Player thisPlayer && toUpdate instanceof Player)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(thisPlayer);
|
||||||
|
if(carry.isCarrying(CarryType.PLAYER)) {
|
||||||
|
this.clampRotation(toUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private void clampRotation(Entity pEntityToUpdate) {
|
||||||
|
Entity thisEntity = (Entity)((Object)this);
|
||||||
|
pEntityToUpdate.setYBodyRot(thisEntity.getYRot());
|
||||||
|
float f = Mth.wrapDegrees(pEntityToUpdate.getYRot() - thisEntity.getYRot());
|
||||||
|
float f1 = Mth.clamp(f, -30.0F, 30.0F);
|
||||||
|
pEntityToUpdate.yRotO += f1 - f;
|
||||||
|
pEntityToUpdate.setYRot(pEntityToUpdate.getYRot() + f1 - f);
|
||||||
|
pEntityToUpdate.setYHeadRot(pEntityToUpdate.getYRot());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.client.model.HumanoidModel;
|
||||||
|
import net.minecraft.client.model.geom.ModelPart;
|
||||||
|
import net.minecraft.client.renderer.entity.state.HumanoidRenderState;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.client.render.ICarryOnRenderState;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.common.scripting.CarryOnScript.ScriptRender;
|
||||||
|
|
||||||
|
@Mixin(HumanoidModel.class)
|
||||||
|
public class HumanoidModelMixin {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public ModelPart rightArm;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public ModelPart leftArm;
|
||||||
|
|
||||||
|
@Inject(at = @At("RETURN"), method = "setupAnim(Lnet/minecraft/client/renderer/entity/state/HumanoidRenderState;)V")
|
||||||
|
private void onSetupAnimations(HumanoidRenderState state, CallbackInfo ci)
|
||||||
|
{
|
||||||
|
if(state instanceof ICarryOnRenderState carryOnRenderState && Constants.CLIENT_CONFIG.renderArms)
|
||||||
|
{
|
||||||
|
CarryOnData carry = carryOnRenderState.getCarryOnData();
|
||||||
|
if(carry != null && carry.isCarrying() && !state.isVisuallySwimming && !state.isFallFlying)
|
||||||
|
{
|
||||||
|
boolean sneaking = state.isCrouching;
|
||||||
|
|
||||||
|
float x = 1.0f + (sneaking ? 0.2f : 0.0f) + (carry.isCarrying(CarryOnData.CarryType.BLOCK) ? 0.0f : 0.3f);
|
||||||
|
float z = 0.05f;
|
||||||
|
|
||||||
|
float width = carryOnRenderState.getRenderWidth();
|
||||||
|
float offset = Math.min((width - 1) / 1.5f, 0.2f);
|
||||||
|
|
||||||
|
if(carry.getActiveScript().isPresent())
|
||||||
|
{
|
||||||
|
ScriptRender render = carry.getActiveScript().get().scriptRender();
|
||||||
|
boolean renderLeft = render.renderLeftArm();
|
||||||
|
boolean renderRight = render.renderRightArm();
|
||||||
|
|
||||||
|
Vec3 rotLeft = render.renderRotationLeftArm().getVec(-x, -offset, z);
|
||||||
|
Vec3 rotRight = render.renderRotationRightArm().getVec(-x, offset, -z);
|
||||||
|
|
||||||
|
if(renderLeft)
|
||||||
|
changeRotation(leftArm, (float) rotLeft.x, (float) rotLeft.y, (float) rotLeft.z);
|
||||||
|
|
||||||
|
if(renderRight)
|
||||||
|
changeRotation(rightArm, (float) rotRight.x, (float) rotRight.y, (float) rotRight.z);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
changeRotation(rightArm, -x, offset, -z);
|
||||||
|
changeRotation(leftArm, -x, -offset, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private void changeRotation(ModelPart part, float x, float y, float z)
|
||||||
|
{
|
||||||
|
part.xRot = x;
|
||||||
|
part.yRot = y;
|
||||||
|
part.zRot = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.mixin;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||||
|
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||||
|
import net.minecraft.core.NonNullList;
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnDataManager;
|
||||||
|
|
||||||
|
@Mixin(Inventory.class)
|
||||||
|
public class InventoryMixin
|
||||||
|
{
|
||||||
|
@Unique
|
||||||
|
private static final ItemStack DUMMY_STACK = new ItemStack(Blocks.COBBLESTONE, 1);
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public Player player;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public int selected;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public NonNullList<ItemStack> items;
|
||||||
|
|
||||||
|
@WrapOperation(method = "getFreeSlot()I", at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/core/NonNullList;get(I)Ljava/lang/Object;"))
|
||||||
|
private Object getFreeSlotEmptyCheck(NonNullList<Object> instance, int slot, Operation<Object> original)
|
||||||
|
{
|
||||||
|
if(slot == selected && CarryOnDataManager.getCarryData(player).isCarrying())
|
||||||
|
{
|
||||||
|
return DUMMY_STACK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return original.call(instance, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "addAndPickItem(Lnet/minecraft/world/item/ItemStack;)V", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void onPickBlock(CallbackInfo info)
|
||||||
|
{
|
||||||
|
if(CarryOnDataManager.getCarryData(player).isCarrying())
|
||||||
|
info.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "pickSlot(I)V", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void onPickSlot(int slot, CallbackInfo info)
|
||||||
|
{
|
||||||
|
if(CarryOnDataManager.getCarryData(player).isCarrying())
|
||||||
|
info.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "setSelectedSlot(I)V", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void onSwapPaint(int slot, CallbackInfo info)
|
||||||
|
{
|
||||||
|
CarryOnData data = CarryOnDataManager.getCarryData(player);
|
||||||
|
if(data.isCarrying() && data.getSelected() != slot)
|
||||||
|
info.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.mixin;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnDataManager;
|
||||||
|
|
||||||
|
@Mixin(Minecraft.class)
|
||||||
|
public class MinecraftMixin {
|
||||||
|
|
||||||
|
@WrapWithCondition(
|
||||||
|
method = "handleKeybinds()V",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/world/entity/player/Inventory;setSelectedSlot(I)V",
|
||||||
|
ordinal = 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private boolean allowSlotSelection(Inventory inv, int slot) {
|
||||||
|
boolean carrying = CarryOnDataManager.getCarryData(inv.player).isCarrying();
|
||||||
|
|
||||||
|
// Allow if not carrying
|
||||||
|
if (!carrying) return true;
|
||||||
|
|
||||||
|
// Block only if trying to switch away
|
||||||
|
return inv.getSelectedSlot() == slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
68
Common/src/main/java/tschipp/carryon/mixin/PlayerMixin.java
Normal file
68
Common/src/main/java/tschipp/carryon/mixin/PlayerMixin.java
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.world.effect.MobEffects;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.storage.ValueInput;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData.CarryType;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnDataManager;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Mixin(Player.class)
|
||||||
|
public abstract class PlayerMixin extends LivingEntity {
|
||||||
|
|
||||||
|
private PlayerMixin(EntityType<? extends LivingEntity> type, Level level) {
|
||||||
|
super(type, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
//We leave this in here to ensure cross-compatibility if world are upgraded from <1.21.8. Should be removed in the future.
|
||||||
|
@Inject(method = "readAdditionalSaveData(Lnet/minecraft/world/level/storage/ValueInput;)V", at = @At("RETURN"))
|
||||||
|
private void onReadAdditionalSaveData(ValueInput input, CallbackInfo ci)
|
||||||
|
{
|
||||||
|
Optional<CarryOnData> res = input.read("CarryOnData", CarryOnData.CODEC);
|
||||||
|
res.ifPresent(data -> CarryOnDataManager.setCarryData((Player)((Object)this), data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopRiding() {
|
||||||
|
Entity entity = this.getVehicle();
|
||||||
|
if (entity instanceof Player && entity.getPassengers().size() < 2){
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData((Player) entity);
|
||||||
|
if (carry.getType() == CarryType.PLAYER){
|
||||||
|
carry.clear();
|
||||||
|
((Player) entity).removeEffect(MobEffects.SLOWNESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.stopRiding();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.networking;
|
||||||
|
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
|
||||||
|
public interface PacketBase extends CustomPacketPayload {
|
||||||
|
|
||||||
|
void handle(Player player);
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.networking.clientbound;
|
||||||
|
|
||||||
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||||
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.networking.PacketBase;
|
||||||
|
|
||||||
|
public record ClientboundStartRidingPacket(int iden, boolean ride) implements PacketBase
|
||||||
|
{
|
||||||
|
public static final StreamCodec<RegistryFriendlyByteBuf, ClientboundStartRidingPacket> CODEC = StreamCodec.composite(
|
||||||
|
ByteBufCodecs.INT, ClientboundStartRidingPacket::iden,
|
||||||
|
ByteBufCodecs.BOOL, ClientboundStartRidingPacket::ride,
|
||||||
|
ClientboundStartRidingPacket::new
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final CustomPacketPayload.Type<ClientboundStartRidingPacket> TYPE = new Type<>(Constants.PACKET_ID_START_RIDING);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(Player player)
|
||||||
|
{
|
||||||
|
Entity otherPlayer = player.level().getEntity(this.iden);
|
||||||
|
if(otherPlayer != null)
|
||||||
|
if(ride)
|
||||||
|
otherPlayer.startRiding(player);
|
||||||
|
else
|
||||||
|
otherPlayer.stopRiding();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type<ClientboundStartRidingPacket> type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.networking.clientbound;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.DataResult;
|
||||||
|
import net.minecraft.nbt.NbtOps;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||||
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.common.scripting.CarryOnScript;
|
||||||
|
import tschipp.carryon.common.scripting.ScriptManager;
|
||||||
|
import tschipp.carryon.networking.PacketBase;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record ClientboundSyncScriptsPacket(Tag serialized) implements PacketBase
|
||||||
|
{
|
||||||
|
public static final StreamCodec<RegistryFriendlyByteBuf, ClientboundSyncScriptsPacket> CODEC = StreamCodec.composite(
|
||||||
|
ByteBufCodecs.TAG, ClientboundSyncScriptsPacket::serialized,
|
||||||
|
ClientboundSyncScriptsPacket::new
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final CustomPacketPayload.Type<ClientboundSyncScriptsPacket> TYPE = new Type<>(Constants.PACKET_ID_SYNC_SCRIPTS);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(Player player)
|
||||||
|
{
|
||||||
|
DataResult<List<CarryOnScript>> res = Codec.list(CarryOnScript.CODEC).parse(NbtOps.INSTANCE, serialized);
|
||||||
|
List<CarryOnScript> scripts = res.getOrThrow((s) -> {throw new RuntimeException("Failed deserializing carry on scripts on the client: " + s);});
|
||||||
|
ScriptManager.SCRIPTS.clear();
|
||||||
|
ScriptManager.SCRIPTS.addAll(scripts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type<ClientboundSyncScriptsPacket> type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.networking.serverbound;
|
||||||
|
|
||||||
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||||
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnDataManager;
|
||||||
|
import tschipp.carryon.networking.PacketBase;
|
||||||
|
|
||||||
|
public record ServerboundCarryKeyPressedPacket(boolean pressed) implements PacketBase
|
||||||
|
{
|
||||||
|
public static final StreamCodec<RegistryFriendlyByteBuf, ServerboundCarryKeyPressedPacket> CODEC = StreamCodec.composite(
|
||||||
|
ByteBufCodecs.BOOL, ServerboundCarryKeyPressedPacket::pressed,
|
||||||
|
ServerboundCarryKeyPressedPacket::new
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final CustomPacketPayload.Type<ServerboundCarryKeyPressedPacket> TYPE = new Type<>(Constants.PACKET_ID_KEY_PRESSED);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(Player player)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
carry.setKeyPressed(this.pressed);
|
||||||
|
CarryOnDataManager.setCarryData(player, carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type<ServerboundCarryKeyPressedPacket> type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
43
Common/src/main/java/tschipp/carryon/platform/Services.java
Normal file
43
Common/src/main/java/tschipp/carryon/platform/Services.java
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.platform;
|
||||||
|
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.platform.services.IGamestagePlatformHelper;
|
||||||
|
import tschipp.carryon.platform.services.IPlatformHelper;
|
||||||
|
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
public class Services {
|
||||||
|
|
||||||
|
public static final IPlatformHelper PLATFORM = load(IPlatformHelper.class);
|
||||||
|
|
||||||
|
public static final IGamestagePlatformHelper GAMESTAGES = load(IGamestagePlatformHelper.class);
|
||||||
|
|
||||||
|
public static <T> T load(Class<T> clazz) {
|
||||||
|
|
||||||
|
final T loadedService = ServiceLoader.load(clazz)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName()));
|
||||||
|
Constants.LOG.debug("Loaded {} for service {}", loadedService, clazz);
|
||||||
|
return loadedService;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.platform.services;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
|
||||||
|
public interface IGamestagePlatformHelper
|
||||||
|
{
|
||||||
|
boolean hasStage(Player player, String stage);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.platform.services;
|
||||||
|
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.config.BuiltConfig;
|
||||||
|
import tschipp.carryon.networking.PacketBase;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
public interface IPlatformHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the current platform
|
||||||
|
*
|
||||||
|
* @return The name of the current platform.
|
||||||
|
*/
|
||||||
|
String getPlatformName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a mod with the given id is loaded.
|
||||||
|
*
|
||||||
|
* @param modId The mod to check if it is loaded.
|
||||||
|
* @return True if the mod is loaded, false otherwise.
|
||||||
|
*/
|
||||||
|
boolean isModLoaded(String modId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the game is currently in a development environment.
|
||||||
|
*
|
||||||
|
* @return True if in a development environment, false otherwise.
|
||||||
|
*/
|
||||||
|
boolean isDevelopmentEnvironment();
|
||||||
|
|
||||||
|
void registerConfig(BuiltConfig cfg);
|
||||||
|
|
||||||
|
<T extends PacketBase, B extends FriendlyByteBuf> void registerServerboundPacket(CustomPacketPayload.Type<T> type, Class<T> clazz, StreamCodec<B, T> codec, BiConsumer<T, Player> handler, Object... args);
|
||||||
|
|
||||||
|
<T extends PacketBase, B extends FriendlyByteBuf> void registerClientboundPacket(CustomPacketPayload.Type<T> type, Class<T> clazz, StreamCodec<B, T> codec, BiConsumer<T, Player> handler, Object... args);
|
||||||
|
|
||||||
|
void sendPacketToServer(Identifier id, PacketBase packet);
|
||||||
|
|
||||||
|
void sendPacketToPlayer(Identifier id, PacketBase packet, ServerPlayer player);
|
||||||
|
|
||||||
|
default void sendPacketToAllPlayers(Identifier id, PacketBase packet, ServerLevel level) {
|
||||||
|
for(ServerPlayer p : level.players())
|
||||||
|
sendPacketToPlayer(id, packet, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
CarryOnData getCarryData(Player player);
|
||||||
|
|
||||||
|
void setCarryData(Player player, CarryOnData data);
|
||||||
|
|
||||||
|
}
|
||||||
38
Common/src/main/java/tschipp/carryon/utils/StringHelper.java
Normal file
38
Common/src/main/java/tschipp/carryon/utils/StringHelper.java
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.utils;
|
||||||
|
|
||||||
|
public class StringHelper
|
||||||
|
{
|
||||||
|
public static boolean matchesWildcards(String str, String[] wildcards)
|
||||||
|
{
|
||||||
|
for(String w : wildcards)
|
||||||
|
{
|
||||||
|
if(!str.contains(w))
|
||||||
|
return false;
|
||||||
|
int i = str.indexOf(w);
|
||||||
|
str = str.substring(i + w.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/de_de.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/de_de.json
Normal 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"
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/en_ud.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/en_ud.json
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"carryon.category.settings": "sᵷuᴉʇʇǝS",
|
||||||
|
"carryon.category.blacklist": "ʇsᴉꞁʞɔɐꞁᗺ",
|
||||||
|
"carryon.category.modeloverrides": "(pǝɔuɐʌpⱯ) sǝpᴉɹɹǝʌO ꞁǝpoW",
|
||||||
|
"carryon.category.custompickupconditions": "(pǝɔuɐʌpⱯ) suoᴉʇᴉpuoƆ dnʞɔᴉԀ ɯoʇsnƆ",
|
||||||
|
"carryon.category.whitelist": "ʇsᴉꞁǝʇᴉɥM",
|
||||||
|
|
||||||
|
"carryon.general.modeloverrides.modeloverrides": "sǝpᴉɹɹǝʌO ꞁǝpoW",
|
||||||
|
"carryon.general.blacklist.forbiddenentities": "dn ʞɔᴉd ʇouuɐɔ ɹǝʎɐꞁԀ ǝɥʇ ʇɐɥʇ sǝᴉʇᴉʇuƎ",
|
||||||
|
"carryon.general.blacklist.forbiddentiles": "dn ʞɔᴉd ʇouuɐɔ ɹǝʎɐꞁԀ ǝɥʇ ʇɐɥʇ sʞɔoꞁᗺ",
|
||||||
|
"carryon.category.custompickupconditions.custompickupconditionsblocks": "suoᴉʇᴉpuoƆ dnʞɔᴉԀ ʞɔoꞁᗺ ɯoʇsnƆ",
|
||||||
|
"carryon.category.custompickupconditions.custompickupconditionsentities": "suoᴉʇᴉpuoƆ dnʞɔᴉԀ ʎʇᴉʇuƎ ɯoʇsnƆ",
|
||||||
|
|
||||||
|
"key.carry.desc": "ʎɹɹɐƆ",
|
||||||
|
"key.category.carryon.key.carry.category": "uO ʎɹɹɐƆ"
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/en_us.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/en_us.json
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"carryon.category.settings": "Settings",
|
||||||
|
"carryon.category.blacklist": "Blacklist",
|
||||||
|
"carryon.category.modeloverrides": "Model Overrides (Advanced)",
|
||||||
|
"carryon.category.custompickupconditions": "Custom Pickup Conditions (Advanced)",
|
||||||
|
"carryon.category.whitelist": "Whitelist",
|
||||||
|
|
||||||
|
"carryon.general.modeloverrides.modeloverrides": "Model Overrides",
|
||||||
|
"carryon.general.blacklist.forbiddenentities": "Entities that the Player cannot pick up",
|
||||||
|
"carryon.general.blacklist.forbiddentiles": "Blocks that the Player cannot pick up",
|
||||||
|
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Custom Block Pickup Conditions",
|
||||||
|
"carryon.category.custompickupconditions.custompickupconditionsentities": "Custom Entity Pickup Conditions",
|
||||||
|
|
||||||
|
"key.carry.desc": "Carry",
|
||||||
|
"key.category.carryon.key.carry.category": "Carry On"
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/es_ar.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/es_ar.json
Normal 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"
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/es_ec.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/es_ec.json
Normal 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"
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/es_es.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/es_es.json
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"carryon.category.settings": "Configuración",
|
||||||
|
"carryon.category.blacklist": "Lista negra",
|
||||||
|
"carryon.category.modeloverrides": "Reescribir modelo (Avanzado)",
|
||||||
|
"carryon.category.custompickupconditions": "Customizar condiciones de recoger (Avanzado)",
|
||||||
|
"carryon.category.whitelist": "Lista blanca",
|
||||||
|
|
||||||
|
"carryon.general.modeloverrides.modeloverrides": "Reescribir modelo",
|
||||||
|
"carryon.general.blacklist.forbiddenentities": "Entidades que el jugador no puede recoger",
|
||||||
|
"carryon.general.blacklist.forbiddentiles": "Bloques que el jugador no puede recoger",
|
||||||
|
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Customizar condiciones para recoger bloques",
|
||||||
|
"carryon.category.custompickupconditions.custompickupconditionsentities": "Customizar condiciones para recoger entidades",
|
||||||
|
|
||||||
|
"key.carry.desc": "Agarrar",
|
||||||
|
"key.category.carryon.key.carry.category": "Carry On"
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/fr_fr.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/fr_fr.json
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"carryon.category.settings": "Paramètres",
|
||||||
|
"carryon.category.blacklist": "Liste noire",
|
||||||
|
"carryon.category.modeloverrides": "Modèle de Remplacement (Avancé)",
|
||||||
|
"carryon.category.custompickupconditions": "Conditions de ramassage personalisés (Avancé)",
|
||||||
|
"carryon.category.whitelist": "Liste blanche",
|
||||||
|
|
||||||
|
"carryon.general.modeloverrides.modeloverrides": "Modèle de Remplacement",
|
||||||
|
"carryon.general.blacklist.forbiddenentities": "Entités que le joueur ne peut pas saisir",
|
||||||
|
"carryon.general.blacklist.forbiddentiles": "Blocs que le joueur ne peut pas saisir",
|
||||||
|
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Conditions de ramassage de blocs personalisés",
|
||||||
|
"carryon.category.custompickupconditions.custompickupconditionsentities": "Conditions de ramassage d'entités personalisés",
|
||||||
|
|
||||||
|
"key.carry.desc": "Saisir",
|
||||||
|
"key.category.carryon.key.carry.category": "Carry On"
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/hu_hu.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/hu_hu.json
Normal 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"
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/it_it.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/it_it.json
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"carryon.category.settings": "Inpostazioni",
|
||||||
|
"carryon.category.blacklist": "Blacklist",
|
||||||
|
"carryon.category.modeloverrides": "Sostituzioni modello (avanzate)",
|
||||||
|
"carryon.category.custompickupconditions": "Condizioni di prelievo personalizzate (avanzate)",
|
||||||
|
"carryon.category.whitelist": "Whitelist",
|
||||||
|
|
||||||
|
"carryon.general.modeloverrides.modeloverrides": "Sostituzioni modello",
|
||||||
|
"carryon.general.blacklist.forbiddenentities": "Entità che il giocatore non può raccogliere",
|
||||||
|
"carryon.general.blacklist.forbiddentiles": "Blocchi che il giocatore non può raccogliere",
|
||||||
|
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Condizioni di prelievo blocco personalizzate",
|
||||||
|
"carryon.category.custompickupconditions.custompickupconditionsentities": "Condizioni di prelievo entità personalizzate",
|
||||||
|
|
||||||
|
"key.carry.desc": "Afferra",
|
||||||
|
"key.category.carryon.key.carry.category": "Carry On Mod"
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/ja_jp.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/ja_jp.json
Normal 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"
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/ko_kr.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/ko_kr.json
Normal 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"
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/ru_ru.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/ru_ru.json
Normal 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"
|
||||||
|
}
|
||||||
17
Common/src/main/resources/assets/carryon/lang/tr_tr.json
Normal file
17
Common/src/main/resources/assets/carryon/lang/tr_tr.json
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"__comment__": "Translated by @alpeerkaraca",
|
||||||
|
"carryon.category.settings": "Ayarlar",
|
||||||
|
"carryon.category.blacklist": "Kara Liste",
|
||||||
|
"carryon.category.modeloverrides": "Üzerine Yazılan Modeller (Gelişmiş)",
|
||||||
|
"carryon.category.custompickupconditions": "Özel Yerden Alma Durumları (Gelişmiş)",
|
||||||
|
"carryon.category.whitelist": "Beyaz Liste",
|
||||||
|
|
||||||
|
"carryon.general.modeloverrides.modeloverrides": "Modellerin Üzerine Yaz",
|
||||||
|
"carryon.general.blacklist.forbiddenentities": "Oyuncunun Alamayacağı Varlıklar",
|
||||||
|
"carryon.general.blacklist.forbiddentiles": "Oyuncunun Alamayacağı Bloklar",
|
||||||
|
"carryon.category.custompickupconditions.custompickupconditionsblocks": "Özel Blok Alma Durumları",
|
||||||
|
"carryon.category.custompickupconditions.custompickupconditionsentities": "Özel Varlık Alma Durumları",
|
||||||
|
|
||||||
|
"key.carry.desc": "Taşı",
|
||||||
|
"key.category.carryon.key.carry.category": "Carry On"
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/uk_ua.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/uk_ua.json
Normal 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"
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/zh_cn.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/zh_cn.json
Normal 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": "搬运"
|
||||||
|
}
|
||||||
16
Common/src/main/resources/assets/carryon/lang/zh_tw.json
Normal file
16
Common/src/main/resources/assets/carryon/lang/zh_tw.json
Normal 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"
|
||||||
|
}
|
||||||
25
Common/src/main/resources/carryon.mixins.json
Normal file
25
Common/src/main/resources/carryon.mixins.json
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"minVersion": "0.8",
|
||||||
|
"package": "tschipp.carryon.mixin",
|
||||||
|
"compatibilityLevel": "JAVA_21",
|
||||||
|
"mixins": [
|
||||||
|
"EntityMixin",
|
||||||
|
"InventoryMixin",
|
||||||
|
"PlayerMixin"
|
||||||
|
],
|
||||||
|
"client": [
|
||||||
|
"AvatarRendererMixin",
|
||||||
|
"EntityRendererMixin",
|
||||||
|
"HumanoidModelMixin",
|
||||||
|
"MinecraftMixin",
|
||||||
|
"PlayerRenderStateMixin"
|
||||||
|
],
|
||||||
|
"server": [
|
||||||
|
],
|
||||||
|
"plugin": "tschipp.carryon.mixin.CarryOnMixinConfigPlugin",
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 1
|
||||||
|
},
|
||||||
|
"refmap": "${mod_id}.refmap.json"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"replace": false,
|
||||||
|
"values": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"replace": false,
|
||||||
|
"values": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"replace": false,
|
||||||
|
"values": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"replace": false,
|
||||||
|
"values": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"replace": false,
|
||||||
|
"values": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"replace": false,
|
||||||
|
"values": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 170 KiB |
6
Common/src/main/resources/pack.mcmeta
Normal file
6
Common/src/main/resources/pack.mcmeta
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"description": "${mod_name}",
|
||||||
|
"pack_format": 34
|
||||||
|
}
|
||||||
|
}
|
||||||
60
Fabric/build.gradle
Normal file
60
Fabric/build.gradle
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
plugins {
|
||||||
|
id 'multiloader-loader'
|
||||||
|
id 'fabric-loom' version "${loom_version}"
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
name = "Shedaniel"
|
||||||
|
url "https://maven.shedaniel.me/"
|
||||||
|
}
|
||||||
|
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
|
|
||||||
|
maven {
|
||||||
|
name = "Terraformers"
|
||||||
|
url = "https://maven.terraformersmc.com/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
minecraft "com.mojang:minecraft:${minecraft_version}"
|
||||||
|
mappings loom.layered() {
|
||||||
|
officialMojangMappings()
|
||||||
|
parchment("org.parchmentmc.data:parchment-${parchment_mappings_fabric}@zip")
|
||||||
|
}
|
||||||
|
modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}"
|
||||||
|
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}"
|
||||||
|
implementation group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.1'
|
||||||
|
|
||||||
|
modApi("me.shedaniel.cloth:cloth-config-fabric:${cloth_config_version}") {
|
||||||
|
exclude(group: "net.fabricmc.fabric-api")
|
||||||
|
}
|
||||||
|
modApi "com.terraformersmc:modmenu:17.0.0-beta.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
loom {
|
||||||
|
def aw = project(':Common').file("src/main/resources/${mod_id}.accesswidener")
|
||||||
|
if (aw.exists()) {
|
||||||
|
accessWidenerPath.set(aw)
|
||||||
|
}
|
||||||
|
mixin {
|
||||||
|
defaultRefmapName.set("${mod_id}.refmap.json")
|
||||||
|
}
|
||||||
|
runs {
|
||||||
|
client {
|
||||||
|
client()
|
||||||
|
setConfigName("Fabric Client")
|
||||||
|
ideConfigGenerated(true)
|
||||||
|
runDir("run")
|
||||||
|
}
|
||||||
|
server {
|
||||||
|
server()
|
||||||
|
setConfigName("Fabric Server")
|
||||||
|
ideConfigGenerated(true)
|
||||||
|
runDir("run")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon;
|
||||||
|
|
||||||
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||||
|
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import tschipp.carryon.client.keybinds.CarryOnKeybinds;
|
||||||
|
import tschipp.carryon.events.ClientEvents;
|
||||||
|
import tschipp.carryon.networking.PacketBase;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
public class CarryOnFabricClientMod implements ClientModInitializer
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onInitializeClient()
|
||||||
|
{
|
||||||
|
CarryOnKeybinds.registerKeybinds(KeyBindingHelper::registerKeyBinding);
|
||||||
|
ClientEvents.registerEvents();
|
||||||
|
CarryOnCommon.registerClientPackets(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendPacketToServer(PacketBase packet)
|
||||||
|
{
|
||||||
|
ClientPlayNetworking.send(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends PacketBase> void registerClientboundPacket(CustomPacketPayload.Type<T> id, BiConsumer<T, Player> handler)
|
||||||
|
{
|
||||||
|
ClientPlayNetworking.registerGlobalReceiver(id, (T packet, ClientPlayNetworking.Context context) -> {
|
||||||
|
context.client().execute(() -> {
|
||||||
|
handler.accept(packet, context.player());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
74
Fabric/src/main/java/tschipp/carryon/CarryOnFabricMod.java
Normal file
74
Fabric/src/main/java/tschipp/carryon/CarryOnFabricMod.java
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon;
|
||||||
|
|
||||||
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.attachment.v1.AttachmentRegistry;
|
||||||
|
import net.fabricmc.fabric.api.attachment.v1.AttachmentType;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.config.fabric.ConfigLoaderImpl;
|
||||||
|
import tschipp.carryon.events.CommonEvents;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class CarryOnFabricMod implements ModInitializer {
|
||||||
|
|
||||||
|
public static final AttachmentType<CarryOnData> CARRY_ON_DATA_ATTACHMENT_TYPE = AttachmentRegistry.create(
|
||||||
|
Identifier.fromNamespaceAndPath(Constants.MOD_ID, "carry_on_data"),
|
||||||
|
builder -> builder
|
||||||
|
.initializer(() -> new CarryOnData(new CompoundTag()))
|
||||||
|
.persistent(CarryOnData.CODEC)
|
||||||
|
.syncWith(CarryOnData.STREAM_CODEC, (t, p) ->{
|
||||||
|
ServerPlayer player = (ServerPlayer) t;
|
||||||
|
// the isAlive check avoids us syncing attachment data about dead players. Which causes a disconnect
|
||||||
|
// player.tickCount > 0 avoids us syncing attachment data about players the instant they spawn.
|
||||||
|
// Which also causes a disconnect as the player entity may not be synced yet.
|
||||||
|
return p.connection != null && player.isAlive() && !p.isRemoved() && player.tickCount > 0;
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitialize() {
|
||||||
|
|
||||||
|
// This method is invoked by the Fabric mod loader when it is ready
|
||||||
|
// to load your mod. You can access Fabric and Common code in this
|
||||||
|
// project.
|
||||||
|
CarryOnCommon.registerConfig();
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
ConfigLoaderImpl.initialize();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
CommonEvents.registerEvents();
|
||||||
|
CarryOnCommon.registerServerPackets();
|
||||||
|
CarryOnCommon.registerClientPackets(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.compat;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.platform.Services;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
public class ArchitecturyCompat {
|
||||||
|
|
||||||
|
private static Object INVOKER_INSTANCE;
|
||||||
|
private static Method PLACE_BLOCK;
|
||||||
|
private static Method IS_FALSE;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static void setup( ) {
|
||||||
|
try {
|
||||||
|
Class BlockEvent = Class.forName("dev.architectury.event.events.common.BlockEvent");
|
||||||
|
Field PLACE = BlockEvent.getField("PLACE");
|
||||||
|
Method invoker = Class.forName("dev.architectury.event.Event").getMethod("invoker");
|
||||||
|
INVOKER_INSTANCE = invoker.invoke(PLACE.get(BlockEvent));
|
||||||
|
Class PlaceClass = Class.forName("dev.architectury.event.events.common.BlockEvent$Place");
|
||||||
|
PLACE_BLOCK = PlaceClass.getMethod("placeBlock", Level.class, BlockPos.class, BlockState.class, Entity.class);
|
||||||
|
Class EventResult = Class.forName("dev.architectury.event.EventResult");
|
||||||
|
IS_FALSE = EventResult.getMethod("isFalse");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Constants.LOG.warn("Error while initializing Architectury Compat: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean active() {
|
||||||
|
return Services.PLATFORM.isModLoaded("architectury");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean sendPlaceEvent(Level level, BlockPos pos, BlockState state, Player player) {
|
||||||
|
if(!active())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(INVOKER_INSTANCE == null || PLACE_BLOCK == null)
|
||||||
|
setup();
|
||||||
|
|
||||||
|
if(INVOKER_INSTANCE != null && PLACE_BLOCK != null && IS_FALSE != null) {
|
||||||
|
try {
|
||||||
|
Object eventResult = PLACE_BLOCK.invoke(INVOKER_INSTANCE, level, pos, state, player);
|
||||||
|
boolean canceled = (boolean) IS_FALSE.invoke(eventResult);
|
||||||
|
|
||||||
|
return !canceled;
|
||||||
|
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.config.fabric;
|
||||||
|
|
||||||
|
import com.google.gson.*;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import tschipp.carryon.common.config.ListHandler;
|
||||||
|
import tschipp.carryon.config.*;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ConfigLoaderImpl {
|
||||||
|
|
||||||
|
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
|
||||||
|
|
||||||
|
//Default JSON and config data.
|
||||||
|
public static final Map<JsonObject, BuiltConfig> CONFIGS = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
public static void initialize() throws IOException {
|
||||||
|
Path cfgPath = FabricLoader.getInstance().getConfigDir();
|
||||||
|
|
||||||
|
for (Map.Entry<JsonObject, BuiltConfig> entry : CONFIGS.entrySet()) {
|
||||||
|
File cfgFile = new File(cfgPath.toFile(), entry.getValue().fileName+".json");
|
||||||
|
if (!cfgFile.exists()) {
|
||||||
|
cfgPath.toFile().mkdirs();
|
||||||
|
FileUtils.write(cfgFile, GSON.toJson(entry.getKey()), StandardCharsets.UTF_8);
|
||||||
|
} else {
|
||||||
|
JsonObject cfgJson = GSON.fromJson(FileUtils.readFileToString(cfgFile, StandardCharsets.UTF_8), JsonObject.class);
|
||||||
|
if(cfgJson == null)
|
||||||
|
{
|
||||||
|
cfgPath.toFile().mkdirs();
|
||||||
|
FileUtils.write(cfgFile, GSON.toJson(entry.getKey()), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
FileUtils.write(cfgFile, GSON.toJson(loadConfig(entry.getValue(), cfgJson)), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JsonObject loadConfig(BuiltCategory category, JsonObject config) {
|
||||||
|
config.entrySet().forEach((entry) -> {
|
||||||
|
String id = entry.getKey();
|
||||||
|
if (!id.startsWith("//")) {
|
||||||
|
JsonElement value = entry.getValue();
|
||||||
|
if (value instanceof JsonPrimitive configValue) {
|
||||||
|
category.getProperty(id).ifPresent(data -> {
|
||||||
|
if (configValue.isBoolean() && data.getData().type().equals(PropertyType.BOOLEAN))
|
||||||
|
data.setBoolean(configValue.getAsBoolean());
|
||||||
|
if (configValue.isNumber() && data.getData().type().equals(PropertyType.INT)) {
|
||||||
|
int configInt = configValue.getAsInt();
|
||||||
|
if (configInt > data.getData().max() || configInt < data.getData().min()) {
|
||||||
|
try {
|
||||||
|
config.addProperty(id, data.getInt());
|
||||||
|
} catch (IllegalAccessException ignored) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data.setInt(configInt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (configValue.isNumber() && data.getData().type().equals(PropertyType.DOUBLE)) {
|
||||||
|
double configDouble = configValue.getAsDouble();
|
||||||
|
if (configDouble > data.getData().maxD() || configDouble < data.getData().minD()) {
|
||||||
|
try {
|
||||||
|
config.addProperty(id, data.getDouble());
|
||||||
|
} catch (IllegalAccessException ignored) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data.setDouble(configDouble);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (value instanceof JsonObject subConfig) {
|
||||||
|
category.getCategory(id).ifPresent(cat -> loadConfig(cat, subConfig));
|
||||||
|
} else if (value instanceof JsonArray list) {
|
||||||
|
category.getProperty(id).ifPresent(data -> {
|
||||||
|
if(data.getData().type() == PropertyType.STRING_ARRAY)
|
||||||
|
{
|
||||||
|
List<String> ls = new ArrayList<>();
|
||||||
|
for(JsonElement arrEle : list)
|
||||||
|
{
|
||||||
|
if(arrEle instanceof JsonPrimitive p && p.isString())
|
||||||
|
{
|
||||||
|
ls.add(p.getAsString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.setStringArray(ls.toArray(new String[ls.size()]));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void saveConfigs() {
|
||||||
|
try {
|
||||||
|
Path cfgPath = FabricLoader.getInstance().getConfigDir();
|
||||||
|
for (Map.Entry<JsonObject, BuiltConfig> entry : CONFIGS.entrySet()) {
|
||||||
|
File cfgFile = new File(cfgPath.toFile(), entry.getValue().fileName+".json");
|
||||||
|
cfgPath.toFile().mkdirs();
|
||||||
|
FileUtils.write(cfgFile, GSON.toJson(entry.getKey()), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
ListHandler.initConfigLists();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerConfig(BuiltConfig config) {
|
||||||
|
try {
|
||||||
|
JsonObject configJson = new JsonObject();
|
||||||
|
for (PropertyData property : config.properties) buildProperty(configJson, property);
|
||||||
|
for (BuiltCategory category : config.categories) buildCategory(configJson, category);
|
||||||
|
CONFIGS.put(configJson, config);
|
||||||
|
}catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void buildCategory(JsonObject builder, BuiltCategory category) throws IllegalAccessException {
|
||||||
|
JsonObject categoryJson = new JsonObject();
|
||||||
|
if (category.categoryDesc != null) categoryJson.addProperty("//"+category.category, category.categoryDesc);
|
||||||
|
for (PropertyData property : category.properties) buildProperty(categoryJson, property);
|
||||||
|
for (BuiltCategory builtCategory : category.categories) buildCategory(categoryJson, builtCategory);
|
||||||
|
builder.add(category.category, categoryJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static void buildProperty(JsonObject builder, PropertyData data) throws IllegalAccessException {
|
||||||
|
AnnotationData annotationData = data.getData();
|
||||||
|
builder.addProperty("//"+data.getId(), annotationData.description());
|
||||||
|
|
||||||
|
switch (annotationData.type()) {
|
||||||
|
case BOOLEAN:
|
||||||
|
builder.addProperty(data.getId(), data.getBoolean());
|
||||||
|
data.setSetter((b) -> {builder.addProperty(data.getId(), (boolean)b); data.setBoolean((boolean)b);});
|
||||||
|
break;
|
||||||
|
case INT:
|
||||||
|
builder.addProperty(data.getId(), data.getInt());
|
||||||
|
data.setSetter((b) -> {builder.addProperty(data.getId(), (int)b); data.setInt((int)b);});
|
||||||
|
break;
|
||||||
|
case DOUBLE:
|
||||||
|
builder.addProperty(data.getId(), data.getDouble());
|
||||||
|
data.setSetter((b) -> {builder.addProperty(data.getId(), (double)b); data.setDouble((double)b);});
|
||||||
|
break;
|
||||||
|
case STRING_ARRAY:
|
||||||
|
JsonArray arr = new JsonArray();
|
||||||
|
for(String s : data.getStringArray())
|
||||||
|
arr.add(s);
|
||||||
|
builder.add(data.getId(), arr);
|
||||||
|
data.setSetter(list -> {
|
||||||
|
JsonArray overwrite = new JsonArray();
|
||||||
|
for(String s : (List<String>)list)
|
||||||
|
overwrite.add(s);
|
||||||
|
builder.add(data.getId(), overwrite);
|
||||||
|
data.setStringArray(((List<?>) list).toArray(new String[0]));
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalAccessException("Unknown property type.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.events;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
|
import tschipp.carryon.CarryOnCommonClient;
|
||||||
|
|
||||||
|
public class ClientEvents {
|
||||||
|
|
||||||
|
public static void registerEvents()
|
||||||
|
{
|
||||||
|
ClientTickEvents.END_CLIENT_TICK.register(mc -> {
|
||||||
|
CarryOnCommonClient.checkForKeybinds();
|
||||||
|
CarryOnCommonClient.onCarryClientTick();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
177
Fabric/src/main/java/tschipp/carryon/events/CommonEvents.java
Normal file
177
Fabric/src/main/java/tschipp/carryon/events/CommonEvents.java
Normal file
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.events;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||||
|
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents;
|
||||||
|
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
|
||||||
|
import net.fabricmc.fabric.api.event.lifecycle.v1.CommonLifecycleEvents;
|
||||||
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||||
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||||
|
import net.fabricmc.fabric.api.event.player.*;
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||||
|
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.packs.PackType;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import tschipp.carryon.CarryOnCommon;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData.CarryType;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnDataManager;
|
||||||
|
import tschipp.carryon.common.carry.PickupHandler;
|
||||||
|
import tschipp.carryon.common.carry.PlacementHandler;
|
||||||
|
import tschipp.carryon.common.scripting.ScriptReloadListener;
|
||||||
|
import tschipp.carryon.compat.ArchitecturyCompat;
|
||||||
|
import tschipp.carryon.config.ConfigLoader;
|
||||||
|
import tschipp.carryon.scripting.IdentifiableScriptReloadListener;
|
||||||
|
|
||||||
|
public class CommonEvents {
|
||||||
|
|
||||||
|
public static void registerEvents() {
|
||||||
|
|
||||||
|
CommonLifecycleEvents.TAGS_LOADED.register((registries, client) -> {
|
||||||
|
if(!client)
|
||||||
|
ConfigLoader.onConfigLoaded(registries);
|
||||||
|
});
|
||||||
|
|
||||||
|
UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> {
|
||||||
|
|
||||||
|
if(world.isClientSide())
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
|
||||||
|
BlockPos pos = hitResult.getBlockPos();
|
||||||
|
Direction facing = hitResult.getDirection();
|
||||||
|
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if(!carry.isCarrying())
|
||||||
|
{
|
||||||
|
if (PickupHandler.tryPickUpBlock((ServerPlayer) player, pos, world, (pState, pPos) -> {
|
||||||
|
boolean success = PlayerBlockBreakEvents.BEFORE.invoker().beforeBlockBreak(world, player, pPos, pState, world.getBlockEntity(pPos));
|
||||||
|
return success;
|
||||||
|
}))
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(carry.isCarrying(CarryOnData.CarryType.BLOCK))
|
||||||
|
{
|
||||||
|
if(PlacementHandler.tryPlaceBlock((ServerPlayer) player, pos, facing, (pState, pPos) -> {
|
||||||
|
return ArchitecturyCompat.sendPlaceEvent(world, pState, pPos, player);
|
||||||
|
}))
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(PlacementHandler.tryPlaceEntity((ServerPlayer) player, pos, facing, null))
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Fail here, so that we don't interact with placed things
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
UseEntityCallback.EVENT.register((player, level, hand, entity, hitResult) -> {
|
||||||
|
|
||||||
|
if(level.isClientSide())
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if (!carry.isCarrying()) {
|
||||||
|
if (PickupHandler.tryPickupEntity((ServerPlayer) player, entity, null)) {
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(carry.isCarrying(CarryOnData.CarryType.ENTITY) || carry.isCarrying(CarryType.PLAYER))
|
||||||
|
{
|
||||||
|
PlacementHandler.tryStackEntity((ServerPlayer) player, entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
CommandRegistrationCallback.EVENT.register(((dispatcher, registryAccess, environment) -> {
|
||||||
|
CarryOnCommon.registerCommands(dispatcher);
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
ResourceManagerHelper.get(PackType.SERVER_DATA).registerReloadListener(new IdentifiableScriptReloadListener());
|
||||||
|
|
||||||
|
|
||||||
|
ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS.register((player, joined) -> {
|
||||||
|
ScriptReloadListener.syncScriptsWithClient(player);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
ServerTickEvents.END_SERVER_TICK.register(server -> {
|
||||||
|
for(ServerPlayer player : server.getPlayerList().getPlayers())
|
||||||
|
CarryOnCommon.onCarryTick(player);
|
||||||
|
});
|
||||||
|
|
||||||
|
ServerPlayerEvents.COPY_FROM.register(((oldPlayer, newPlayer, alive) -> {
|
||||||
|
PlacementHandler.placeCarriedOnDeath(oldPlayer, newPlayer, !alive);
|
||||||
|
}));
|
||||||
|
|
||||||
|
PlayerBlockBreakEvents.BEFORE.register(((world, player, pos, state, blockEntity) -> {
|
||||||
|
if(!CarryOnCommon.onTryBreakBlock(player))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
|
||||||
|
AttackBlockCallback.EVENT.register(((player, world, hand, pos, direction) -> {
|
||||||
|
if(!CarryOnCommon.onTryBreakBlock(player))
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
}));
|
||||||
|
|
||||||
|
AttackEntityCallback.EVENT.register(((player, world, hand, entity, hitResult) -> {
|
||||||
|
if(!CarryOnCommon.onAttackedByPlayer(player))
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
}));
|
||||||
|
|
||||||
|
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
|
||||||
|
CarryOnCommon.onRiderDisconnected(handler.getPlayer());
|
||||||
|
});
|
||||||
|
|
||||||
|
ServerLivingEntityEvents.ALLOW_DEATH.register((entity, damageSource, damageAmount) -> {
|
||||||
|
if(entity instanceof ServerPlayer sp) {
|
||||||
|
CarryOnCommon.onRiderDisconnected(sp);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
ServerLivingEntityEvents.ALLOW_DAMAGE.register((entity, source, amount) -> {
|
||||||
|
if(entity instanceof ServerPlayer sp) {
|
||||||
|
CarryOnCommon.onPlayerAttacked(sp);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.mixin;
|
||||||
|
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.MixinExtrasBootstrap;
|
||||||
|
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||||
|
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class CarryOnMixinConfigPlugin implements IMixinConfigPlugin {
|
||||||
|
@Override
|
||||||
|
public void onLoad(String mixinPackage) {
|
||||||
|
MixinExtrasBootstrap.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRefMapperConfig() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getMixins() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postApply(String targetClassName, org.objectweb.asm.tree.ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preApply(String targetClassName, org.objectweb.asm.tree.ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.mixin;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.player.AbstractClientPlayer;
|
||||||
|
import net.minecraft.client.renderer.ItemInHandRenderer;
|
||||||
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import tschipp.carryon.client.render.CarriedObjectRender;
|
||||||
|
|
||||||
|
@Mixin(ItemInHandRenderer.class)
|
||||||
|
public class ItemInHandRendererMixin
|
||||||
|
{
|
||||||
|
@Inject(at = @At(value = "HEAD"), method = "renderArmWithItem(Lnet/minecraft/client/player/AbstractClientPlayer;FFLnet/minecraft/world/InteractionHand;FLnet/minecraft/world/item/ItemStack;FLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;I)V", cancellable = true)
|
||||||
|
private void renderArmWithItem(AbstractClientPlayer player, float partialTick, float pitch, InteractionHand hand, float swingProgress, ItemStack item, float equippedProgress, PoseStack poseStack, SubmitNodeCollector nodeCollector, int packedLight, CallbackInfo ci)
|
||||||
|
{
|
||||||
|
if(CarriedObjectRender.draw(player, poseStack, packedLight, partialTick,nodeCollector,true))
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnDataManager;
|
||||||
|
import tschipp.carryon.common.carry.PlacementHandler;
|
||||||
|
|
||||||
|
@Mixin(Player.class)
|
||||||
|
public class PlayerMixinFabric
|
||||||
|
{
|
||||||
|
@Inject(at = @At("HEAD"), method = "hurtServer(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/damagesource/DamageSource;F)Z")
|
||||||
|
private void onHurt(ServerLevel level, DamageSource damageSource, float amount, CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
if(Constants.COMMON_CONFIG.settings.dropCarriedWhenHit)
|
||||||
|
{
|
||||||
|
Player player = ((Player)(Object)this);
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if(carry.isCarrying())
|
||||||
|
PlacementHandler.placeCarried((ServerPlayer)player);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
49
Fabric/src/main/java/tschipp/carryon/mixin/ScreenMixin.java
Normal file
49
Fabric/src/main/java/tschipp/carryon/mixin/ScreenMixin.java
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnDataManager;
|
||||||
|
|
||||||
|
@Mixin(Screen.class)
|
||||||
|
public class ScreenMixin
|
||||||
|
{
|
||||||
|
@Inject(at = @At(value = "TAIL"), method = "init(II)V")
|
||||||
|
private void onInit(int width, int height, CallbackInfo ci)
|
||||||
|
{
|
||||||
|
Minecraft mc = Minecraft.getInstance();
|
||||||
|
Player player = mc.player;
|
||||||
|
if((Object)this instanceof AbstractContainerScreen && player != null)
|
||||||
|
{
|
||||||
|
CarryOnData carry = CarryOnDataManager.getCarryData(player);
|
||||||
|
if(carry.isCarrying())
|
||||||
|
mc.setScreen((Screen)null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.platform;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import tschipp.carryon.platform.services.IGamestagePlatformHelper;
|
||||||
|
|
||||||
|
public class FabricGamestagesHelper implements IGamestagePlatformHelper
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean hasStage(Player player, String stage)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.platform;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||||
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import tschipp.carryon.CarryOnFabricClientMod;
|
||||||
|
import tschipp.carryon.CarryOnFabricMod;
|
||||||
|
import tschipp.carryon.common.carry.CarryOnData;
|
||||||
|
import tschipp.carryon.config.BuiltConfig;
|
||||||
|
import tschipp.carryon.config.fabric.ConfigLoaderImpl;
|
||||||
|
import tschipp.carryon.networking.PacketBase;
|
||||||
|
import tschipp.carryon.platform.services.IPlatformHelper;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
public class FabricPlatformHelper implements IPlatformHelper {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPlatformName() {
|
||||||
|
return "Fabric";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isModLoaded(String modId) {
|
||||||
|
|
||||||
|
return FabricLoader.getInstance().isModLoaded(modId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDevelopmentEnvironment() {
|
||||||
|
|
||||||
|
return FabricLoader.getInstance().isDevelopmentEnvironment();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerConfig(BuiltConfig cfg) {
|
||||||
|
ConfigLoaderImpl.registerConfig(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public <T extends PacketBase, B extends FriendlyByteBuf> void registerServerboundPacket(CustomPacketPayload.Type<T> type, Class<T> clazz, StreamCodec<B, T> codec, BiConsumer<T, Player> handler, Object... args)
|
||||||
|
{
|
||||||
|
PayloadTypeRegistry.playC2S().register(type, (StreamCodec<RegistryFriendlyByteBuf, T>)codec);
|
||||||
|
|
||||||
|
ServerPlayNetworking.registerGlobalReceiver(type, (T packet, ServerPlayNetworking.Context context) -> {
|
||||||
|
context.server().execute(() -> {
|
||||||
|
handler.accept(packet, context.player());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public <T extends PacketBase, B extends FriendlyByteBuf> void registerClientboundPacket(CustomPacketPayload.Type<T> type, Class<T> clazz, StreamCodec<B, T> codec, BiConsumer<T, Player> handler, Object... args)
|
||||||
|
{
|
||||||
|
boolean client = (boolean)args[0];
|
||||||
|
|
||||||
|
if(!client)
|
||||||
|
PayloadTypeRegistry.playS2C().register(type, (StreamCodec<RegistryFriendlyByteBuf, T>)codec);
|
||||||
|
else
|
||||||
|
CarryOnFabricClientMod.registerClientboundPacket(type, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendPacketToServer(Identifier id, PacketBase packet)
|
||||||
|
{
|
||||||
|
CarryOnFabricClientMod.sendPacketToServer(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendPacketToPlayer(Identifier id, PacketBase packet, ServerPlayer player)
|
||||||
|
{
|
||||||
|
ServerPlayNetworking.send(player, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CarryOnData getCarryData(Player player) {
|
||||||
|
CarryOnData data = player.getAttachedOrCreate(CarryOnFabricMod.CARRY_ON_DATA_ATTACHMENT_TYPE);
|
||||||
|
return data.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCarryData(Player player, CarryOnData data) {
|
||||||
|
player.setAttached(CarryOnFabricMod.CARRY_ON_DATA_ATTACHMENT_TYPE, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* GNU Lesser General Public License v3
|
||||||
|
* Copyright (C) 2024 Tschipp
|
||||||
|
* mrtschipp@gmail.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tschipp.carryon.scripting;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
import tschipp.carryon.Constants;
|
||||||
|
import tschipp.carryon.common.scripting.ScriptReloadListener;
|
||||||
|
|
||||||
|
public class IdentifiableScriptReloadListener extends ScriptReloadListener implements IdentifiableResourceReloadListener
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Identifier getFabricId()
|
||||||
|
{
|
||||||
|
return Identifier.fromNamespaceAndPath(Constants.MOD_ID, "carryon_scripts");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
tschipp.carryon.platform.FabricGamestagesHelper
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
tschipp.carryon.platform.FabricPlatformHelper
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user