Skip to content

Commit 68c5387

Browse files
authored
Merge pull request #24 from box3lab/dev_coolfish
Dev coolfish
2 parents b85c950 + 0eb81ba commit 68c5387

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1995
-979
lines changed

Fabric-1.20.1/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ loader_version=0.18.4
1212
loom_version=1.15-SNAPSHOT
1313

1414
# Mod Properties
15-
mod_version=1.4.1-mc1.20.1
15+
mod_version=1.4.2-mc1.20.1
1616
maven_group=com.box3lab
1717
archives_base_name=box3
1818

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
package com.box3lab.block.entity;
2+
3+
import java.util.Locale;
4+
import java.util.Map;
5+
import java.util.UUID;
6+
import java.util.concurrent.ConcurrentHashMap;
7+
8+
import com.box3lab.register.modelbe.PackModelBlockEntityRegistrar;
9+
10+
import net.minecraft.commands.CommandSourceStack;
11+
import net.minecraft.core.BlockPos;
12+
import net.minecraft.core.Direction;
13+
import net.minecraft.network.chat.Component;
14+
import net.minecraft.server.MinecraftServer;
15+
import net.minecraft.server.level.ServerLevel;
16+
import net.minecraft.world.entity.Display;
17+
import net.minecraft.world.entity.EntityType;
18+
import net.minecraft.world.item.ItemStack;
19+
import net.minecraft.world.level.Level;
20+
import net.minecraft.world.level.block.state.BlockState;
21+
import net.minecraft.world.level.block.entity.BlockEntity;
22+
import net.minecraft.world.phys.AABB;
23+
import net.minecraft.world.phys.Vec3;
24+
25+
public class PackModelBlockEntity extends BlockEntity {
26+
private static final long RESPAWN_INTERVAL_TICKS = 20L;
27+
private static final String DISPLAY_TAG_PREFIX = "box3_pack_model:";
28+
29+
private static final float SCALE_STEP = 0.1F;
30+
private static final float SCALE_MIN = 0.1F;
31+
private static final float SCALE_MAX = 4.0F;
32+
private static final float OFFSET_STEP = 0.05F;
33+
private static final float ROTATION_STEP = 15.0F;
34+
private static final Map<UUID, ConfigSnapshot> CONFIG_CLIPBOARD = new ConcurrentHashMap<>();
35+
36+
private float scale = 1.0F;
37+
private float offsetX = 0.0F;
38+
private float offsetY = 0.0F;
39+
private float offsetZ = 0.0F;
40+
private float rotationOffset = 0.0F;
41+
private int modeIndex = 0;
42+
43+
public PackModelBlockEntity(BlockPos pos, BlockState state) {
44+
super(PackModelBlockEntityRegistrar.typeFor(state.getBlock()), pos, state);
45+
}
46+
47+
@Override
48+
public void setRemoved() {
49+
removeDisplaysAt(this.level, this.getBlockPos());
50+
super.setRemoved();
51+
}
52+
53+
public static void serverTick(Level level, BlockPos pos, BlockState state, PackModelBlockEntity blockEntity) {
54+
if (!(level instanceof ServerLevel serverLevel)) {
55+
return;
56+
}
57+
58+
String tag = displayTag(pos);
59+
var displays = findDisplays(serverLevel, pos, tag);
60+
61+
if (displays.isEmpty()) {
62+
if (serverLevel.getGameTime() % RESPAWN_INTERVAL_TICKS != 0) {
63+
return;
64+
}
65+
spawnDisplay(serverLevel, pos, state, blockEntity, tag);
66+
return;
67+
}
68+
69+
for (Display.ItemDisplay display : displays) {
70+
blockEntity.applyPose(serverLevel, pos, state, display);
71+
}
72+
}
73+
74+
public void cycleMode(net.minecraft.world.entity.player.Player player) {
75+
this.modeIndex = (this.modeIndex + 1) % Mode.values().length;
76+
this.setChanged();
77+
player.displayClientMessage(Component.translatable(
78+
"message.box3.model.config.mode",
79+
Component.translatable(currentMode().translationKey())), true);
80+
}
81+
82+
public void adjustCurrentMode(ServerLevel level, BlockPos pos, BlockState state, int direction,
83+
net.minecraft.world.entity.player.Player player) {
84+
Mode mode = currentMode();
85+
switch (mode) {
86+
case SCALE -> this.scale = clamp(this.scale + SCALE_STEP * direction, SCALE_MIN, SCALE_MAX);
87+
case OFFSET_X -> this.offsetX += OFFSET_STEP * direction;
88+
case OFFSET_Y -> this.offsetY += OFFSET_STEP * direction;
89+
case OFFSET_Z -> this.offsetZ += OFFSET_STEP * direction;
90+
case ROTATION -> this.rotationOffset = normalizeDegrees(this.rotationOffset + ROTATION_STEP * direction);
91+
}
92+
93+
this.setChanged();
94+
player.displayClientMessage(statusComponent(), true);
95+
applyToDisplays(level, pos, state);
96+
}
97+
98+
public void copyConfig(net.minecraft.world.entity.player.Player player) {
99+
CONFIG_CLIPBOARD.put(player.getUUID(),
100+
new ConfigSnapshot(this.scale, this.offsetX, this.offsetY, this.offsetZ, this.rotationOffset));
101+
player.displayClientMessage(Component.translatable("message.box3.model.config.copy.success"), true);
102+
}
103+
104+
public void pasteConfig(ServerLevel level, BlockPos pos, BlockState state,
105+
net.minecraft.world.entity.player.Player player) {
106+
ConfigSnapshot snapshot = CONFIG_CLIPBOARD.get(player.getUUID());
107+
if (snapshot == null) {
108+
player.displayClientMessage(Component.translatable("message.box3.model.config.copy.empty"), true);
109+
return;
110+
}
111+
112+
this.scale = clamp(snapshot.scale, SCALE_MIN, SCALE_MAX);
113+
this.offsetX = snapshot.offsetX;
114+
this.offsetY = snapshot.offsetY;
115+
this.offsetZ = snapshot.offsetZ;
116+
this.rotationOffset = normalizeDegrees(snapshot.rotationOffset);
117+
this.setChanged();
118+
119+
applyToDisplays(level, pos, state);
120+
player.displayClientMessage(Component.translatable("message.box3.model.config.copy.pasted"), true);
121+
player.displayClientMessage(statusComponent(), true);
122+
}
123+
124+
public static void removeDisplaysAt(Level level, BlockPos pos) {
125+
if (!(level instanceof ServerLevel serverLevel)) {
126+
return;
127+
}
128+
129+
String tag = displayTag(pos);
130+
for (Display.ItemDisplay display : findDisplays(serverLevel, pos, tag)) {
131+
display.discard();
132+
}
133+
}
134+
135+
private static void spawnDisplay(ServerLevel level, BlockPos pos, BlockState state, PackModelBlockEntity be,
136+
String tag) {
137+
Display.ItemDisplay display = EntityType.ITEM_DISPLAY.create(level);
138+
if (display == null) {
139+
return;
140+
}
141+
142+
display.setNoGravity(true);
143+
display.setInvulnerable(true);
144+
display.getSlot(0).set(new ItemStack(state.getBlock()));
145+
display.addTag(tag);
146+
147+
be.applyPose(level, pos, state, display);
148+
level.addFreshEntity(display);
149+
}
150+
151+
private void applyPose(ServerLevel level, BlockPos pos, BlockState state, Display.ItemDisplay display) {
152+
double x = pos.getX() + 0.5D;
153+
double y = pos.getY() + this.offsetY;
154+
double z = pos.getZ() + 0.5D;
155+
display.setPos(x, y, z);
156+
157+
float baseYaw = 0.0F;
158+
if (state.hasProperty(PackModelEntityBlock.HORIZONTAL_FACING)) {
159+
Direction facing = state.getValue(PackModelEntityBlock.HORIZONTAL_FACING);
160+
baseYaw = facing.toYRot();
161+
}
162+
display.setYRot(normalizeDegrees(baseYaw + this.rotationOffset));
163+
164+
applyDisplayTransformation(level, display);
165+
}
166+
167+
private void applyDisplayTransformation(ServerLevel level, Display.ItemDisplay display) {
168+
MinecraftServer server = level.getServer();
169+
CommandSourceStack source = server.createCommandSourceStack().withSuppressedOutput()
170+
.withPermission(4);
171+
172+
String cmd = String.format(
173+
Locale.ROOT,
174+
"data merge entity %s {item_display:\"fixed\",transformation:{translation:[%sf,%sf,%sf],left_rotation:[0f,0f,0f,1f],scale:[%sf,%sf,%sf],right_rotation:[0f,0f,0f,1f]}}",
175+
display.getStringUUID(),
176+
fmt(this.offsetX), fmt(0.0F), fmt(this.offsetZ),
177+
fmt(this.scale), fmt(this.scale), fmt(this.scale));
178+
server.getCommands().performPrefixedCommand(source, cmd);
179+
}
180+
181+
private static String fmt(float value) {
182+
return String.format(Locale.ROOT, "%.3f", value);
183+
}
184+
185+
private static java.util.List<Display.ItemDisplay> findDisplays(ServerLevel level, BlockPos pos, String tag) {
186+
return level.getEntitiesOfClass(
187+
Display.ItemDisplay.class,
188+
new AABB(pos).inflate(0.25D),
189+
display -> display.getTags().contains(tag));
190+
}
191+
192+
private void applyToDisplays(ServerLevel level, BlockPos pos, BlockState state) {
193+
for (Display.ItemDisplay display : findDisplays(level, pos, displayTag(pos))) {
194+
applyPose(level, pos, state, display);
195+
}
196+
}
197+
198+
private Mode currentMode() {
199+
return Mode.values()[this.modeIndex];
200+
}
201+
202+
private Component statusComponent() {
203+
return Component.translatable(
204+
"message.box3.model.config.status",
205+
Component.translatable(currentMode().translationKey()),
206+
String.format(Locale.ROOT, "%.2f", this.scale),
207+
String.format(Locale.ROOT, "%.2f", this.offsetX),
208+
String.format(Locale.ROOT, "%.2f", this.offsetY),
209+
String.format(Locale.ROOT, "%.2f", this.offsetZ),
210+
String.format(Locale.ROOT, "%.1f", this.rotationOffset));
211+
}
212+
213+
private static float clamp(float value, float min, float max) {
214+
return Math.max(min, Math.min(max, value));
215+
}
216+
217+
private static float normalizeDegrees(float value) {
218+
float v = value % 360.0F;
219+
return v < 0.0F ? v + 360.0F : v;
220+
}
221+
222+
private static String displayTag(BlockPos pos) {
223+
return DISPLAY_TAG_PREFIX + pos.asLong();
224+
}
225+
226+
private enum Mode {
227+
SCALE("scale"),
228+
OFFSET_X("offset_x"),
229+
OFFSET_Y("offset_y"),
230+
OFFSET_Z("offset_z"),
231+
ROTATION("rotation");
232+
233+
private final String keyPart;
234+
235+
Mode(String keyPart) {
236+
this.keyPart = keyPart;
237+
}
238+
239+
public String translationKey() {
240+
return "message.box3.model.config.mode." + this.keyPart;
241+
}
242+
}
243+
244+
private record ConfigSnapshot(float scale, float offsetX, float offsetY, float offsetZ, float rotationOffset) {
245+
}
246+
}

0 commit comments

Comments
 (0)