Skip to content

Commit 67e23ee

Browse files
authored
Add 1.21.10 (#759)
* Add 1.21.9 * Replace 1.21.9 with 1.21.10
1 parent de2b338 commit 67e23ee

File tree

7 files changed

+484
-1
lines changed

7 files changed

+484
-1
lines changed

Movecraft/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ dependencies {
1313
runtimeOnly(project(":movecraft-v1_21_4", "reobf"))
1414
runtimeOnly(project(":movecraft-v1_21_5", "reobf"))
1515
runtimeOnly(project(":movecraft-v1_21_8", "reobf"))
16+
runtimeOnly(project(":movecraft-v1_21_10", "reobf"))
1617
implementation(project(":movecraft-api"))
1718
compileOnly("org.yaml:snakeyaml:2.0")
1819
}
@@ -29,6 +30,7 @@ tasks.shadowJar {
2930
include(project(":movecraft-v1_21_4"))
3031
include(project(":movecraft-v1_21_5"))
3132
include(project(":movecraft-v1_21_8"))
33+
include(project(":movecraft-v1_21_10"))
3234
}
3335
}
3436

@@ -72,7 +74,7 @@ hangarPublish {
7274
platforms {
7375
register(io.papermc.hangarpublishplugin.model.Platforms.PAPER) {
7476
jar.set(tasks.shadowJar.flatMap { it.archiveFile })
75-
platformVersions.set(listOf("1.20.6", "1.21.1", "1.21.4", "1.21.5", "1.21.8"))
77+
platformVersions.set(listOf("1.20.6", "1.21.1", "1.21.4", "1.21.5", "1.21.8", "1.21.10"))
7678
}
7779
}
7880
}

settings.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ include(":movecraft-v1_21_1")
44
include(":movecraft-v1_21_4")
55
include(":movecraft-v1_21_5")
66
include(":movecraft-v1_21_8")
7+
include(":movecraft-v1_21_10")
78
include(":movecraft-api")
89
include(":movecraft-datapack")
910
include(":movecraft")
@@ -12,6 +13,7 @@ project(":movecraft-v1_21_1").projectDir = file("v1_21_1")
1213
project(":movecraft-v1_21_4").projectDir = file("v1_21_4")
1314
project(":movecraft-v1_21_5").projectDir = file("v1_21_5")
1415
project(":movecraft-v1_21_8").projectDir = file("v1_21_8")
16+
project(":movecraft-v1_21_10").projectDir = file("v1_21_10")
1517
project(":movecraft-api").projectDir = file("api")
1618
project(":movecraft-datapack").projectDir = file("datapack")
1719
project(":movecraft").projectDir = file("Movecraft")

v1_21_10/build.gradle.kts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
plugins {
2+
id("buildlogic.java-conventions")
3+
id("io.papermc.paperweight.userdev")
4+
}
5+
6+
java.toolchain.languageVersion = JavaLanguageVersion.of(21)
7+
8+
dependencies {
9+
api(project(":movecraft-api"))
10+
paperweight.paperDevBundle("1.21.10-R0.1-SNAPSHOT")
11+
}
12+
13+
description = "Movecraft-v1_21_10"
14+
paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.MOJANG_PRODUCTION
Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
package net.countercraft.movecraft.compat.v1_21_10;
2+
3+
import ca.spottedleaf.moonrise.common.util.WorldUtil;
4+
import net.countercraft.movecraft.MovecraftLocation;
5+
import net.countercraft.movecraft.MovecraftRotation;
6+
import net.countercraft.movecraft.WorldHandler;
7+
import net.countercraft.movecraft.craft.Craft;
8+
import net.countercraft.movecraft.util.CollectionUtils;
9+
import net.countercraft.movecraft.util.MathUtils;
10+
import net.countercraft.movecraft.util.UnsafeUtils;
11+
import net.minecraft.core.BlockPos;
12+
import net.minecraft.server.level.ServerLevel;
13+
import net.minecraft.world.level.Level;
14+
import net.minecraft.world.level.block.Block;
15+
import net.minecraft.world.level.block.Blocks;
16+
import net.minecraft.world.level.block.Rotation;
17+
import net.minecraft.world.level.block.entity.BlockEntity;
18+
import net.minecraft.world.level.block.piston.PistonBaseBlock;
19+
import net.minecraft.world.level.block.piston.PistonMovingBlockEntity;
20+
import net.minecraft.world.level.block.state.BlockState;
21+
import net.minecraft.world.level.chunk.LevelChunk;
22+
import net.minecraft.world.level.chunk.LevelChunkSection;
23+
import net.minecraft.world.ticks.LevelChunkTicks;
24+
import net.minecraft.world.ticks.ScheduledTick;
25+
import org.bukkit.Bukkit;
26+
import org.bukkit.Location;
27+
import org.bukkit.block.data.BlockData;
28+
import org.bukkit.craftbukkit.CraftWorld;
29+
import org.bukkit.craftbukkit.block.data.CraftBlockData;
30+
import org.jetbrains.annotations.NotNull;
31+
import org.jetbrains.annotations.Nullable;
32+
33+
import java.util.ArrayList;
34+
import java.util.Collection;
35+
import java.util.HashMap;
36+
import java.util.List;
37+
import java.util.Map;
38+
import java.util.function.Predicate;
39+
40+
@SuppressWarnings("unused")
41+
public class IWorldHandler extends WorldHandler {
42+
private static final Rotation ROTATION[];
43+
44+
static {
45+
ROTATION = new Rotation[3];
46+
ROTATION[MovecraftRotation.NONE.ordinal()] = Rotation.NONE;
47+
ROTATION[MovecraftRotation.CLOCKWISE.ordinal()] = Rotation.CLOCKWISE_90;
48+
ROTATION[MovecraftRotation.ANTICLOCKWISE.ordinal()] = Rotation.COUNTERCLOCKWISE_90;
49+
}
50+
51+
private final NextTickProvider tickProvider = new NextTickProvider();
52+
53+
public IWorldHandler() {
54+
String version = Bukkit.getServer().getMinecraftVersion();
55+
if (!version.equals("1.21.10"))
56+
throw new IllegalStateException("Movecraft is not compatible with this version of Minecraft: " + version);
57+
}
58+
59+
@Override
60+
public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull MovecraftRotation rotation) {
61+
//*******************************************
62+
//* Step one: Convert to Positions *
63+
//*******************************************
64+
HashMap<BlockPos, BlockPos> rotatedPositions = new HashMap<>();
65+
MovecraftRotation counterRotation = rotation == MovecraftRotation.CLOCKWISE ? MovecraftRotation.ANTICLOCKWISE : MovecraftRotation.CLOCKWISE;
66+
for (MovecraftLocation newLocation : craft.getHitBox()) {
67+
rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)), locationToPosition(newLocation));
68+
}
69+
//*******************************************
70+
//* Step two: Get the tiles *
71+
//*******************************************
72+
ServerLevel nativeWorld = ((CraftWorld) craft.getWorld()).getHandle();
73+
List<TileHolder> tiles = new ArrayList<>();
74+
List<TickHolder> ticks = new ArrayList<>();
75+
//get the tiles
76+
for (BlockPos position : rotatedPositions.keySet()) {
77+
//BlockEntity tile = nativeWorld.removeBlockEntity(position);
78+
BlockEntity tile = removeBlockEntity(nativeWorld, position);
79+
if (tile != null)
80+
tiles.add(new TileHolder(tile, position));
81+
82+
//get the nextTick to move with the tile
83+
ScheduledTick tickHere = tickProvider.getNextTick(nativeWorld, position);
84+
if (tickHere != null) {
85+
((LevelChunkTicks) nativeWorld.getChunkAt(position).getBlockTicks()).removeIf(
86+
(Predicate<ScheduledTick>) scheduledTick -> scheduledTick.equals(tickHere));
87+
ticks.add(new TickHolder(tickHere, position));
88+
}
89+
}
90+
91+
//*******************************************
92+
//* Step three: Translate all the blocks *
93+
//*******************************************
94+
// blockedByWater=false means an ocean-going vessel
95+
//TODO: Simplify
96+
//TODO: go by chunks
97+
//TODO: Don't move unnecessary blocks
98+
//get the blocks and rotate them
99+
HashMap<BlockPos, BlockState> blockData = new HashMap<>();
100+
for (BlockPos position : rotatedPositions.keySet()) {
101+
blockData.put(position, nativeWorld.getBlockState(position).rotate(ROTATION[rotation.ordinal()]));
102+
}
103+
//create the new block
104+
for (Map.Entry<BlockPos, BlockState> entry : blockData.entrySet()) {
105+
setBlockFast(nativeWorld, rotatedPositions.get(entry.getKey()), entry.getValue());
106+
}
107+
108+
109+
//*******************************************
110+
//* Step four: replace all the tiles *
111+
//*******************************************
112+
//TODO: go by chunks
113+
for (TileHolder tileHolder : tiles)
114+
moveBlockEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()), tileHolder.getTile());
115+
for (TickHolder tickHolder : ticks) {
116+
final long currentTime = nativeWorld.serverLevelData.getGameTime();
117+
nativeWorld.getBlockTicks().schedule(new ScheduledTick<>(
118+
(Block) tickHolder.getTick().type(),
119+
rotatedPositions.get(tickHolder.getTick().pos()),
120+
tickHolder.getTick().triggerTick() - currentTime,
121+
tickHolder.getTick().priority(),
122+
tickHolder.getTick().subTickOrder()));
123+
}
124+
125+
//*******************************************
126+
//* Step five: Destroy the leftovers *
127+
//*******************************************
128+
//TODO: add support for pass-through
129+
Collection<BlockPos> deletePositions = CollectionUtils.filter(rotatedPositions.keySet(), rotatedPositions.values());
130+
for (BlockPos position : deletePositions) {
131+
setBlockFast(nativeWorld, position, Blocks.AIR.defaultBlockState());
132+
}
133+
}
134+
135+
@Override
136+
public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement, @NotNull org.bukkit.World world) {
137+
//TODO: Add support for rotations
138+
//A craftTranslateCommand should only occur if the craft is moving to a valid position
139+
//*******************************************
140+
//* Step one: Convert to Positions *
141+
//*******************************************
142+
BlockPos translateVector = locationToPosition(displacement);
143+
List<BlockPos> positions = new ArrayList<>(craft.getHitBox().size());
144+
craft.getHitBox().forEach((movecraftLocation) -> positions.add(locationToPosition((movecraftLocation)).subtract(translateVector)));
145+
ServerLevel oldNativeWorld = ((CraftWorld) craft.getWorld()).getHandle();
146+
ServerLevel nativeWorld = ((CraftWorld) world).getHandle();
147+
//*******************************************
148+
//* Step two: Get the tiles *
149+
//*******************************************
150+
List<TileHolder> tiles = new ArrayList<>();
151+
List<TickHolder> ticks = new ArrayList<>();
152+
//get the tiles
153+
for (int i = 0, positionsSize = positions.size(); i < positionsSize; i++) {
154+
BlockPos position = positions.get(i);
155+
if (oldNativeWorld.getBlockState(position) == Blocks.AIR.defaultBlockState())
156+
continue;
157+
//BlockEntity tile = nativeWorld.removeBlockEntity(position);
158+
BlockEntity tile = removeBlockEntity(oldNativeWorld, position);
159+
if (tile != null)
160+
tiles.add(new TileHolder(tile,position));
161+
162+
//get the nextTick to move with the tile
163+
ScheduledTick tickHere = tickProvider.getNextTick(nativeWorld, position);
164+
if (tickHere != null) {
165+
((LevelChunkTicks) nativeWorld.getChunkAt(position).getBlockTicks()).removeIf(
166+
(Predicate<ScheduledTick>) scheduledTick -> scheduledTick.equals(tickHere));
167+
ticks.add(new TickHolder(tickHere, position));
168+
}
169+
}
170+
//*******************************************
171+
//* Step three: Translate all the blocks *
172+
//*******************************************
173+
// blockedByWater=false means an ocean-going vessel
174+
//TODO: Simplify
175+
//TODO: go by chunks
176+
//TODO: Don't move unnecessary blocks
177+
//get the blocks and translate the positions
178+
List<BlockState> blockData = new ArrayList<>();
179+
List<BlockPos> newPositions = new ArrayList<>();
180+
for (int i = 0, positionsSize = positions.size(); i < positionsSize; i++) {
181+
BlockPos position = positions.get(i);
182+
blockData.add(oldNativeWorld.getBlockState(position));
183+
newPositions.add(position.offset(translateVector));
184+
}
185+
//create the new block
186+
for (int i = 0, positionSize = newPositions.size(); i < positionSize; i++) {
187+
setBlockFast(nativeWorld, newPositions.get(i), blockData.get(i));
188+
}
189+
//*******************************************
190+
//* Step four: replace all the tiles *
191+
//*******************************************
192+
//TODO: go by chunks
193+
for (TileHolder tileHolder : tiles)
194+
moveBlockEntity(nativeWorld, tileHolder.getTilePosition().offset(translateVector), tileHolder.getTile());
195+
for (TickHolder tickHolder : ticks) {
196+
final long currentTime = nativeWorld.getGameTime();
197+
nativeWorld.getBlockTicks().schedule(new ScheduledTick<>((Block) tickHolder.getTick().type(), tickHolder.getTickPosition().offset(translateVector), tickHolder.getTick().triggerTick() - currentTime, tickHolder.getTick().priority(), tickHolder.getTick().subTickOrder()));
198+
}
199+
//*******************************************
200+
//* Step five: Destroy the leftovers *
201+
//*******************************************
202+
List<BlockPos> deletePositions = positions;
203+
if (oldNativeWorld == nativeWorld)
204+
deletePositions = CollectionUtils.filter(positions, newPositions);
205+
for (int i = 0, deletePositionsSize = deletePositions.size(); i < deletePositionsSize; i++) {
206+
BlockPos position = deletePositions.get(i);
207+
setBlockFast(oldNativeWorld, position, Blocks.AIR.defaultBlockState());
208+
}
209+
}
210+
211+
@Nullable
212+
private BlockEntity removeBlockEntity(@NotNull Level world, @NotNull BlockPos position) {
213+
BlockEntity testEntity = world.getChunkAt(position).getBlockEntity(position);
214+
//Prevents moving pistons by locking up by forcing their movement to finish
215+
if (testEntity instanceof PistonMovingBlockEntity)
216+
{
217+
BlockState oldState;
218+
if (((PistonMovingBlockEntity) testEntity).isSourcePiston() && testEntity.getBlockState().getBlock() instanceof PistonBaseBlock) {
219+
if (((PistonMovingBlockEntity) testEntity).getMovedState().is(Blocks.PISTON))
220+
oldState = Blocks.PISTON.defaultBlockState()
221+
.setValue(PistonBaseBlock.FACING, ((PistonMovingBlockEntity) testEntity).getMovedState().getValue(PistonBaseBlock.FACING));
222+
else
223+
oldState = Blocks.STICKY_PISTON.defaultBlockState()
224+
.setValue(PistonBaseBlock.FACING, ((PistonMovingBlockEntity) testEntity).getMovedState().getValue(PistonBaseBlock.FACING));
225+
} else
226+
oldState = ((PistonMovingBlockEntity) testEntity).getMovedState();
227+
((PistonMovingBlockEntity) testEntity).finalTick();
228+
setBlockFast(world, position, oldState);
229+
return world.getBlockEntity(position);
230+
}
231+
return world.getChunkAt(position).blockEntities.remove(position);
232+
}
233+
234+
@NotNull
235+
private BlockPos locationToPosition(@NotNull MovecraftLocation loc) {
236+
return new BlockPos(loc.getX(), loc.getY(), loc.getZ());
237+
}
238+
239+
private void setBlockFast(@NotNull Level world, @NotNull BlockPos position, @NotNull BlockState data) {
240+
LevelChunk chunk = world.getChunkAt(position);
241+
int chunkSection = (position.getY() >> 4) - WorldUtil.getMinSection(world);
242+
LevelChunkSection section = chunk.getSections()[chunkSection];
243+
if (section == null) {
244+
// Put a GLASS block to initialize the section. It will be replaced next with the real block.
245+
chunk.setBlockState(position, Blocks.GLASS.defaultBlockState(), 0);
246+
section = chunk.getSections()[chunkSection];
247+
}
248+
if (section.getBlockState(position.getX() & 15, position.getY() & 15, position.getZ() & 15).equals(data)) {
249+
//Block is already of correct type and data, don't overwrite
250+
return;
251+
}
252+
section.setBlockState(position.getX() & 15, position.getY() & 15, position.getZ() & 15, data);
253+
world.sendBlockUpdated(position, data, data, 3);
254+
world.getLightEngine().checkBlock(position); // boolean corresponds to if chunk section empty
255+
chunk.markUnsaved();
256+
}
257+
258+
@Override
259+
public void setBlockFast(@NotNull Location location, @NotNull BlockData data) {
260+
setBlockFast(location, MovecraftRotation.NONE, data);
261+
}
262+
263+
@Override
264+
public void setBlockFast(@NotNull Location location, @NotNull MovecraftRotation rotation, @NotNull BlockData data) {
265+
BlockState blockData;
266+
if (data instanceof CraftBlockData) {
267+
blockData = ((CraftBlockData) data).getState();
268+
}
269+
else {
270+
blockData = (BlockState) data;
271+
}
272+
blockData = blockData.rotate(ROTATION[rotation.ordinal()]);
273+
Level world = ((CraftWorld) (location.getWorld())).getHandle();
274+
BlockPos BlockPos = locationToPosition(MathUtils.bukkit2MovecraftLoc(location));
275+
setBlockFast(world, BlockPos, blockData);
276+
}
277+
278+
private void moveBlockEntity(@NotNull Level nativeWorld, @NotNull BlockPos newPosition, @NotNull BlockEntity tile) {
279+
LevelChunk chunk = nativeWorld.getChunkAt(newPosition);
280+
try {
281+
var positionField = BlockEntity.class.getDeclaredField("o"); // o is obfuscated worldPosition
282+
UnsafeUtils.setField(positionField, tile, newPosition);
283+
}
284+
catch (NoSuchFieldException e) {
285+
e.printStackTrace();
286+
}
287+
tile.setLevel(nativeWorld);
288+
tile.clearRemoved();
289+
if (nativeWorld.captureBlockStates) {
290+
nativeWorld.capturedTileEntities.put(newPosition, tile);
291+
return;
292+
}
293+
chunk.setBlockEntity(tile);
294+
chunk.blockEntities.put(newPosition, tile);
295+
}
296+
297+
private static class TileHolder {
298+
@NotNull
299+
private final BlockEntity tile;
300+
@NotNull
301+
private final BlockPos tilePosition;
302+
303+
public TileHolder(@NotNull BlockEntity tile, @NotNull BlockPos tilePosition) {
304+
this.tile = tile;
305+
this.tilePosition = tilePosition;
306+
}
307+
308+
309+
@NotNull
310+
public BlockEntity getTile() {
311+
return tile;
312+
}
313+
314+
@NotNull
315+
public BlockPos getTilePosition() {
316+
return tilePosition;
317+
}
318+
}
319+
320+
private static class TickHolder {
321+
@NotNull
322+
private final ScheduledTick tick;
323+
@NotNull
324+
private final BlockPos tickPosition;
325+
326+
public TickHolder(@NotNull ScheduledTick tick, @NotNull BlockPos tilePosition) {
327+
this.tick = tick;
328+
this.tickPosition = tilePosition;
329+
}
330+
331+
332+
@NotNull
333+
public ScheduledTick getTick() {
334+
return tick;
335+
}
336+
337+
@NotNull
338+
public BlockPos getTickPosition() {
339+
return tickPosition;
340+
}
341+
}
342+
}

0 commit comments

Comments
 (0)