mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-28 19:39:11 +00:00
add crop block
This commit is contained in:
@@ -34,46 +34,16 @@ public class CropBlockBehavior extends BushBlockBehavior {
|
||||
this.minGrowLight = minGrowLight;
|
||||
}
|
||||
|
||||
public final boolean isMaxAge(Object state) {
|
||||
return this.getAge(state) >= this.ageProperty.max;
|
||||
}
|
||||
|
||||
public final boolean isMaxAge(ImmutableBlockState state) {
|
||||
return this.getAge(state) >= this.ageProperty.max;
|
||||
}
|
||||
|
||||
public static ImmutableBlockState getCEBlockState(Object nmsState) {
|
||||
return BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(nmsState));
|
||||
}
|
||||
|
||||
public final int getAge(Object state) {
|
||||
return getCEBlockState(state).get(ageProperty);
|
||||
}
|
||||
|
||||
public final int getAge(ImmutableBlockState state) {
|
||||
return state.get(ageProperty);
|
||||
}
|
||||
|
||||
public Object getStateForAge(Object state, int age) {
|
||||
ImmutableBlockState afterState = getCEBlockState(state).owner().value().defaultState().with(ageProperty, age);
|
||||
return afterState.customBlockState().handle();
|
||||
}
|
||||
|
||||
public void growCrops(Object level, Object pos, Object state) throws InvocationTargetException, IllegalAccessException {
|
||||
int i = this.getAge(state) + RandomUtils.generateRandomInt(2, 5);
|
||||
int maxAge = this.ageProperty.max;
|
||||
if (i > maxAge) {
|
||||
i = maxAge;
|
||||
}
|
||||
Reflections.method$Level$setBlock.invoke(level, pos, getStateForAge(state, i), UpdateOption.UPDATE_NONE.flags());
|
||||
}
|
||||
|
||||
private static int getRawBrightness(Object level, Object pos) throws InvocationTargetException, IllegalAccessException {
|
||||
return (int) Reflections.method$BlockAndTintGetter$getRawBrightness.invoke(level, pos, 0);
|
||||
}
|
||||
|
||||
private boolean hasSufficientLight(Object level, Object pos) throws InvocationTargetException, IllegalAccessException {
|
||||
return getRawBrightness(level, pos) >= minGrowLight - 1;
|
||||
return getRawBrightness(level, pos) >= this.minGrowLight - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,11 +51,13 @@ public class CropBlockBehavior extends BushBlockBehavior {
|
||||
Object state = args[0];
|
||||
Object level = args[1];
|
||||
Object pos = args[2];
|
||||
if (getRawBrightness(level, pos) >= minGrowLight) {
|
||||
int age = this.getAge(state);
|
||||
float randomFloat = RandomUtils.generateRandomFloat(0, 1);
|
||||
if (age < this.ageProperty.max && randomFloat < 1.0 / Math.floor(25.0 / this.growSpeed + 1.0)) {
|
||||
Reflections.method$Level$setBlock.invoke(level, pos, getStateForAge(state, age + 1), UpdateOption.UPDATE_ALL.flags());
|
||||
if (getRawBrightness(level, pos) >= this.minGrowLight) {
|
||||
ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (currentState != null && !currentState.isEmpty()) {
|
||||
int age = this.getAge(currentState);
|
||||
if (age < this.ageProperty.max && RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) {
|
||||
Reflections.method$Level$setBlock.invoke(level, pos, currentState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,12 +75,30 @@ public class CropBlockBehavior extends BushBlockBehavior {
|
||||
@Override
|
||||
public boolean isValidBoneMealTarget(Object thisBlock, Object[] args) {
|
||||
Object state = args[2];
|
||||
return !this.isMaxAge(state);
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (immutableBlockState != null && !immutableBlockState.isEmpty()) {
|
||||
return getAge(immutableBlockState) != this.ageProperty.max;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performBoneMeal(Object thisBlock, Object[] args) throws Exception {
|
||||
this.growCrops(args[0], args[2], args[3]);
|
||||
this.performBoneMeal(args[0], args[2], args[3]);
|
||||
}
|
||||
|
||||
private void performBoneMeal(Object level, Object pos, Object state) throws InvocationTargetException, IllegalAccessException {
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int i = this.getAge(immutableBlockState) + RandomUtils.generateRandomInt(2, 5);
|
||||
int maxAge = this.ageProperty.max;
|
||||
if (i > maxAge) {
|
||||
i = maxAge;
|
||||
}
|
||||
Reflections.method$Level$setBlock.invoke(level, pos, immutableBlockState.with(this.ageProperty, i).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags());
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
@@ -122,8 +112,8 @@ public class CropBlockBehavior extends BushBlockBehavior {
|
||||
throw new IllegalArgumentException("age property not set for crop");
|
||||
}
|
||||
// 存活条件是最小生长亮度-1
|
||||
int minGrowLight = MiscUtils.getAsInt(arguments.getOrDefault("min-grow-light", 9));
|
||||
float growSpeed = MiscUtils.getAsFloat(arguments.getOrDefault("grow-speed", 1));
|
||||
int minGrowLight = MiscUtils.getAsInt(arguments.getOrDefault("light-requirement", 9));
|
||||
float growSpeed = MiscUtils.getAsFloat(arguments.getOrDefault("grow-speed", 0.25f));
|
||||
return new CropBlockBehavior(tuple.left(), tuple.mid(), tuple.right(), ageProperty, growSpeed, minGrowLight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@ import net.momirealms.craftengine.core.plugin.config.ConfigManager;
|
||||
import net.momirealms.craftengine.core.util.SectionPosUtils;
|
||||
import net.momirealms.craftengine.core.world.CEWorld;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor;
|
||||
|
||||
public class BukkitCEWorld extends CEWorld {
|
||||
|
||||
public BukkitCEWorld(World world) {
|
||||
super(world);
|
||||
public BukkitCEWorld(World world, StorageAdaptor adaptor) {
|
||||
super(world, adaptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.momirealms.craftengine.bukkit.world;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.compatibility.slimeworld.SlimeFormatStorageAdaptor;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector;
|
||||
@@ -8,6 +9,7 @@ import net.momirealms.craftengine.bukkit.util.Reflections;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.plugin.config.ConfigManager;
|
||||
import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.CEWorld;
|
||||
import net.momirealms.craftengine.core.world.ChunkPos;
|
||||
import net.momirealms.craftengine.core.world.SectionPos;
|
||||
@@ -15,6 +17,8 @@ import net.momirealms.craftengine.core.world.WorldManager;
|
||||
import net.momirealms.craftengine.core.world.chunk.CEChunk;
|
||||
import net.momirealms.craftengine.core.world.chunk.CESection;
|
||||
import net.momirealms.craftengine.core.world.chunk.serialization.ChunkSerializer;
|
||||
import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor;
|
||||
import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
@@ -27,6 +31,7 @@ import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||
import org.bukkit.event.world.WorldLoadEvent;
|
||||
import org.bukkit.event.world.WorldUnloadEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
@@ -38,18 +43,34 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
private static BukkitWorldManager instance;
|
||||
private final BukkitCraftEngine plugin;
|
||||
private final Map<UUID, CEWorld> worlds;
|
||||
private CEWorld[] worldArray;
|
||||
private CEWorld[] worldArray = new CEWorld[0];
|
||||
private final ReentrantReadWriteLock worldMapLock = new ReentrantReadWriteLock();
|
||||
private SchedulerTask tickTask;
|
||||
// cache
|
||||
private UUID lastVisitedUUID;
|
||||
private CEWorld lastVisitedWorld;
|
||||
private StorageAdaptor storageAdaptor;
|
||||
|
||||
public BukkitWorldManager(BukkitCraftEngine plugin) {
|
||||
instance = this;
|
||||
this.plugin = plugin;
|
||||
this.worlds = new HashMap<>();
|
||||
resetWorldArray();
|
||||
if (VersionHelper.isVersionNewerThan1_21_4()) {
|
||||
try {
|
||||
Class.forName("com.infernalsuite.asp.api.AdvancedSlimePaperAPI");
|
||||
SlimeFormatStorageAdaptor adaptor = new SlimeFormatStorageAdaptor(this);
|
||||
this.storageAdaptor = adaptor;
|
||||
Bukkit.getPluginManager().registerEvents(adaptor, plugin.bootstrap());
|
||||
return;
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
this.storageAdaptor = new DefaultStorageAdaptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStorageAdaptor(@NotNull StorageAdaptor storageAdaptor) {
|
||||
this.storageAdaptor = storageAdaptor;
|
||||
}
|
||||
|
||||
public static BukkitWorldManager instance() {
|
||||
@@ -95,7 +116,7 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
this.worldMapLock.writeLock().lock();
|
||||
try {
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
CEWorld ceWorld = new BukkitCEWorld(new BukkitWorld(world));
|
||||
CEWorld ceWorld = new BukkitCEWorld(new BukkitWorld(world), this.storageAdaptor);
|
||||
this.worlds.put(world.getUID(), ceWorld);
|
||||
this.resetWorldArray();
|
||||
for (Chunk chunk : world.getLoadedChunks()) {
|
||||
@@ -110,8 +131,11 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
@Override
|
||||
public void disable() {
|
||||
HandlerList.unregisterAll(this);
|
||||
if (tickTask != null && !tickTask.cancelled()) {
|
||||
tickTask.cancel();
|
||||
if (this.storageAdaptor instanceof Listener listener) {
|
||||
HandlerList.unregisterAll(listener);
|
||||
}
|
||||
if (this.tickTask != null && !this.tickTask.cancelled()) {
|
||||
this.tickTask.cancel();
|
||||
}
|
||||
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
@@ -125,14 +149,18 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||
public void onWorldLoad(WorldLoadEvent event) {
|
||||
World world = event.getWorld();
|
||||
CEWorld ceWorld = new BukkitCEWorld(new BukkitWorld(world));
|
||||
this.loadWorld(new BukkitWorld(event.getWorld()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWorld(net.momirealms.craftengine.core.world.World world) {
|
||||
this.worldMapLock.writeLock().lock();
|
||||
try {
|
||||
if (this.worlds.containsKey(world.getUID())) return;
|
||||
this.worlds.put(event.getWorld().getUID(), ceWorld);
|
||||
if (this.worlds.containsKey(world.uuid())) return;
|
||||
CEWorld ceWorld = new BukkitCEWorld(world, this.storageAdaptor);
|
||||
this.worlds.put(world.uuid(), ceWorld);
|
||||
this.resetWorldArray();
|
||||
for (Chunk chunk : world.getLoadedChunks()) {
|
||||
for (Chunk chunk : ((World) world.platformWorld()).getLoadedChunks()) {
|
||||
handleChunkLoad(ceWorld, chunk);
|
||||
}
|
||||
} finally {
|
||||
@@ -142,11 +170,15 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
public void onWorldUnload(WorldUnloadEvent event) {
|
||||
World world = event.getWorld();
|
||||
unloadWorld(new BukkitWorld(event.getWorld()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unloadWorld(net.momirealms.craftengine.core.world.World world) {
|
||||
CEWorld ceWorld;
|
||||
this.worldMapLock.writeLock().lock();
|
||||
try {
|
||||
ceWorld = this.worlds.remove(world.getUID());
|
||||
ceWorld = this.worlds.remove(world.uuid());
|
||||
if (ceWorld == null) {
|
||||
return;
|
||||
}
|
||||
@@ -158,11 +190,20 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
} finally {
|
||||
this.worldMapLock.writeLock().unlock();
|
||||
}
|
||||
for (Chunk chunk : world.getLoadedChunks()) {
|
||||
for (Chunk chunk : ((World) world.platformWorld()).getLoadedChunks()) {
|
||||
handleChunkUnload(ceWorld, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> net.momirealms.craftengine.core.world.World wrap(T world) {
|
||||
if (world instanceof World w) {
|
||||
return new BukkitWorld(w);
|
||||
} else {
|
||||
throw new IllegalArgumentException(world.getClass() + " is not a Bukkit World");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||
public void onChunkLoad(ChunkLoadEvent event) {
|
||||
this.worldMapLock.readLock().lock();
|
||||
|
||||
Reference in New Issue
Block a user