This commit is contained in:
Felix Cravic 2020-08-07 09:14:50 +02:00
parent 12ccbfc80e
commit 45fd0dc22a
23 changed files with 119 additions and 70 deletions

View File

@ -4,7 +4,6 @@ import fr.themode.demo.entity.ChickenCreature;
import fr.themode.demo.generator.ChunkGeneratorDemo; import fr.themode.demo.generator.ChunkGeneratorDemo;
import fr.themode.demo.generator.NoiseTestGenerator; import fr.themode.demo.generator.NoiseTestGenerator;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.advancements.*;
import net.minestom.server.benchmark.BenchmarkManager; import net.minestom.server.benchmark.BenchmarkManager;
import net.minestom.server.benchmark.ThreadResult; import net.minestom.server.benchmark.ThreadResult;
import net.minestom.server.chat.ChatColor; import net.minestom.server.chat.ChatColor;
@ -69,7 +68,6 @@ public class PlayerInit {
end.loadChunk(x, z); end.loadChunk(x, z);
} }
inventory = new Inventory(InventoryType.CHEST_1_ROW, "Test inventory"); inventory = new Inventory(InventoryType.CHEST_1_ROW, "Test inventory");
inventory.addInventoryCondition((p, slot, clickType, inventoryConditionResult) -> { inventory.addInventoryCondition((p, slot, clickType, inventoryConditionResult) -> {
p.sendMessage("click type inventory: " + clickType); p.sendMessage("click type inventory: " + clickType);
@ -149,10 +147,8 @@ public class PlayerInit {
p.teleport(player.getPosition()); p.teleport(player.getPosition());
}*/ }*/
for (int i = 0; i < 100; i++) {
ChickenCreature chickenCreature = new ChickenCreature(player.getPosition()); ChickenCreature chickenCreature = new ChickenCreature(player.getPosition());
chickenCreature.setInstance(player.getInstance()); chickenCreature.setInstance(player.getInstance());
}
/*EntityZombie zombie = new EntityZombie(player.getPosition()); /*EntityZombie zombie = new EntityZombie(player.getPosition());
zombie.setAttribute(Attribute.MOVEMENT_SPEED, 0.25f); zombie.setAttribute(Attribute.MOVEMENT_SPEED, 0.25f);
@ -228,7 +224,7 @@ public class PlayerInit {
scoreboard.setTitle("test");*/ scoreboard.setTitle("test");*/
{ {
AdvancementManager advancementManager = MinecraftServer.getAdvancementManager(); /*AdvancementManager advancementManager = MinecraftServer.getAdvancementManager();
AdvancementRoot root = new AdvancementRoot(ColoredText.of("title"), ColoredText.of(ChatColor.BLUE + "description"), AdvancementRoot root = new AdvancementRoot(ColoredText.of("title"), ColoredText.of(ChatColor.BLUE + "description"),
Material.APPLE, FrameType.TASK, 0, 0, Material.APPLE, FrameType.TASK, 0, 0,
"minecraft:textures/block/red_wool.png"); "minecraft:textures/block/red_wool.png");
@ -247,9 +243,7 @@ public class PlayerInit {
ColoredText.of("description of the advancement"), ColoredText.of("description of the advancement"),
Material.GOLD_BLOCK, FrameType.CHALLENGE, 3, 0) Material.GOLD_BLOCK, FrameType.CHALLENGE, 3, 0)
.showToast(true).setHidden(false); .showToast(true).setHidden(false);
tab.createAdvancement("second2", advancement2, root); tab.createAdvancement("second2", advancement2, root);*/
//player.getPlayerConnection().sendPacket(tab.removePacket());
} }
}); });

View File

@ -192,7 +192,7 @@ public class MinecraftServer {
/** /**
* Change the server brand name, update the name to all connected players * Change the server brand name, update the name to all connected players
* *
* @param brandName * @param brandName the server brand name
*/ */
public static void setBrandName(String brandName) { public static void setBrandName(String brandName) {
Check.notNull(brandName, "The brand name cannot be null"); Check.notNull(brandName, "The brand name cannot be null");

View File

@ -5,7 +5,6 @@ import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.EntityManager; import net.minestom.server.entity.EntityManager;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance; import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.packet.server.play.KeepAlivePacket; import net.minestom.server.network.packet.server.play.KeepAlivePacket;
import net.minestom.server.thread.PerGroupChunkProvider; import net.minestom.server.thread.PerGroupChunkProvider;
@ -19,6 +18,7 @@ public final class UpdateManager {
private static final long KEEP_ALIVE_DELAY = 10_000; private static final long KEEP_ALIVE_DELAY = 10_000;
private static final long KEEP_ALIVE_KICK = 30_000; private static final long KEEP_ALIVE_KICK = 30_000;
private static final ColoredText TIMEOUT_TEXT = ColoredText.of(ChatColor.RED + "Timeout");
private ExecutorService mainUpdate = new MinestomThread(1, MinecraftServer.THREAD_NAME_MAIN_UPDATE); private ExecutorService mainUpdate = new MinestomThread(1, MinecraftServer.THREAD_NAME_MAIN_UPDATE);
private boolean stopRequested; private boolean stopRequested;
@ -36,12 +36,14 @@ public final class UpdateManager {
protected UpdateManager() { protected UpdateManager() {
} }
public void start() { /**
* Start the server loop in the update thread
*/
protected void start() {
mainUpdate.execute(() -> { mainUpdate.execute(() -> {
final ConnectionManager connectionManager = MinecraftServer.getConnectionManager(); final ConnectionManager connectionManager = MinecraftServer.getConnectionManager();
final EntityManager entityManager = MinecraftServer.getEntityManager(); final EntityManager entityManager = MinecraftServer.getEntityManager();
final InstanceManager instanceManager = MinecraftServer.getInstanceManager();
final long tickDistance = MinecraftServer.TICK_MS * 1000000; final long tickDistance = MinecraftServer.TICK_MS * 1000000;
long currentTime; long currentTime;
@ -49,10 +51,10 @@ public final class UpdateManager {
currentTime = System.nanoTime(); currentTime = System.nanoTime();
final long time = System.currentTimeMillis(); final long time = System.currentTimeMillis();
// Server tick // Server tick (instance/chunk/entity)
threadProvider.update(time); threadProvider.update(time);
// Waiting players update // Waiting players update (newly connected waiting to get into the server)
entityManager.updateWaitingPlayers(); entityManager.updateWaitingPlayers();
// Keep Alive Handling // Keep Alive Handling
@ -63,7 +65,7 @@ public final class UpdateManager {
player.refreshKeepAlive(time); player.refreshKeepAlive(time);
player.getPlayerConnection().sendPacket(keepAlivePacket); player.getPlayerConnection().sendPacket(keepAlivePacket);
} else if (lastKeepAlive >= KEEP_ALIVE_KICK) { } else if (lastKeepAlive >= KEEP_ALIVE_KICK) {
player.kick(ColoredText.of(ChatColor.RED + "Timeout")); player.kick(TIMEOUT_TEXT);
} }
} }
@ -127,7 +129,9 @@ public final class UpdateManager {
this.threadProvider.onChunkUnload(instance, chunkX, chunkZ); this.threadProvider.onChunkUnload(instance, chunkX, chunkZ);
} }
/**
* Stop the server loop
*/
public void stop() { public void stop() {
stopRequested = true; stopRequested = true;
} }

View File

@ -121,13 +121,13 @@ public class CollisionUtils {
} }
/** /**
* Steps once (by a length of 1 block) on the given axis. Returns false if this method encountered a collision * Steps once (by a length of 1 block) on the given axis.
* *
* @param instance instance to get blocks from * @param instance instance to get blocks from
* @param axis the axis to move along * @param axis the axis to move along
* @param cornersCopy the corners of the bounding box to consider (mutable) * @param cornersCopy the corners of the bounding box to consider (mutable)
* @param cornerPositions the corners, converted to BlockPosition (mutable) * @param cornerPositions the corners, converted to BlockPosition (mutable)
* @return * @return false if this method encountered a collision
*/ */
private static boolean stepOnce(Instance instance, Vector axis, float amount, Vector[] cornersCopy, BlockPosition[] cornerPositions) { private static boolean stepOnce(Instance instance, Vector axis, float amount, Vector[] cornersCopy, BlockPosition[] cornerPositions) {
final float sign = Math.signum(amount); final float sign = Math.signum(amount);

View File

@ -68,8 +68,8 @@ public class Data {
/** /**
* Get if the data has a key * Get if the data has a key
* *
* @param key * @param key the key to check
* @return true if the data contains the key, false otherwise * @return true if the data contains the key
*/ */
public boolean hasKey(String key) { public boolean hasKey(String key) {
return data.containsKey(key); return data.containsKey(key);

View File

@ -1125,8 +1125,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
/** /**
* Trigger {@link #remove()} after the specified time * Trigger {@link #remove()} after the specified time
* *
* @param delay * @param delay the time before removing the entity
* @param timeUnit to determine the delay unit * @param timeUnit the unit of the delay
*/ */
public void scheduleRemove(long delay, TimeUnit timeUnit) { public void scheduleRemove(long delay, TimeUnit timeUnit) {
delay = timeUnit.toMilliseconds(delay); delay = timeUnit.toMilliseconds(delay);

View File

@ -234,8 +234,8 @@ public class ItemEntity extends ObjectEntity {
/** /**
* Set the pickup delay of the ItemEntity * Set the pickup delay of the ItemEntity
* *
* @param delay * @param delay the pickup delay
* @param timeUnit * @param timeUnit the unit of the delay
*/ */
public void setPickupDelay(long delay, TimeUnit timeUnit) { public void setPickupDelay(long delay, TimeUnit timeUnit) {
this.pickupDelay = timeUnit.toMilliseconds(delay); this.pickupDelay = timeUnit.toMilliseconds(delay);

View File

@ -1669,7 +1669,7 @@ public class Player extends LivingEntity implements CommandSender {
* <p> * <p>
* WARNING: this has nothing to do with {@link CustomBlock#getBreakDelay(Player, BlockPosition)} * WARNING: this has nothing to do with {@link CustomBlock#getBreakDelay(Player, BlockPosition)}
* *
* @param instantBreak * @param instantBreak true to allow instant break
*/ */
public void setInstantBreak(boolean instantBreak) { public void setInstantBreak(boolean instantBreak) {
this.instantBreak = instantBreak; this.instantBreak = instantBreak;

View File

@ -27,8 +27,10 @@ public interface EventHandler {
<E extends Event> void removeEventCallback(Class<E> eventClass, EventCallback<E> eventCallback); <E extends Event> void removeEventCallback(Class<E> eventClass, EventCallback<E> eventCallback);
/** /**
* @param eventClass * Get the event callbacks of a specific event type
* @param <E> *
* @param eventClass the event class
* @param <E> the event type
* @return all event callbacks for the specified type {@code eventClass} * @return all event callbacks for the specified type {@code eventClass}
*/ */
<E extends Event> List<EventCallback> getEventCallbacks(Class<E> eventClass); <E extends Event> List<EventCallback> getEventCallbacks(Class<E> eventClass);

View File

@ -76,7 +76,7 @@ public class PlayerBlockPlaceEvent extends CancellableEvent {
* WARNING: this does not change the visual block id, see {@link #setBlockId(short)} * WARNING: this does not change the visual block id, see {@link #setBlockId(short)}
* or {@link #setCustomBlock(short)} * or {@link #setCustomBlock(short)}
* *
* @param customBlockId * @param customBlockId the custom block id
*/ */
public void setCustomBlockId(short customBlockId) { public void setCustomBlockId(short customBlockId) {
this.customBlockId = customBlockId; this.customBlockId = customBlockId;

View File

@ -4,13 +4,14 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import net.minestom.server.network.packet.server.play.TagsPacket; import net.minestom.server.network.packet.server.play.TagsPacket;
import net.minestom.server.registry.ResourceGatherer; import net.minestom.server.registry.ResourceGatherer;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.NamespaceID;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.*; import java.io.File;
import java.util.HashMap; import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -177,17 +178,19 @@ public class TagManager {
/** /**
* Loads a tag with the given name. This method attempts to read from "data/&lt;name.domain&gt;/tags/&lt;tagType&gt;/&lt;name.path&gt;.json" if the given name is not already present in cache * Loads a tag with the given name. This method attempts to read from "data/&lt;name.domain&gt;/tags/&lt;tagType&gt;/&lt;name.path&gt;.json" if the given name is not already present in cache
*
* @param name * @param name
* @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants) * @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants)
* @return * @return
* @throws FileNotFoundException if the file does not exist * @throws FileNotFoundException if the file does not exist
*/ */
public Tag load(NamespaceID name, String tagType) throws FileNotFoundException { public Tag load(NamespaceID name, String tagType) throws FileNotFoundException {
return load(name, tagType, () -> new FileReader(new File(ResourceGatherer.DATA_FOLDER, "data/"+name.getDomain()+"/tags/"+tagType+"/"+name.getPath()+".json"))); return load(name, tagType, () -> new FileReader(new File(ResourceGatherer.DATA_FOLDER, "data/" + name.getDomain() + "/tags/" + tagType + "/" + name.getPath() + ".json")));
} }
/** /**
* Loads a tag with the given name. This method attempts to read from 'reader' if the given name is not already present in cache * Loads a tag with the given name. This method attempts to read from 'reader' if the given name is not already present in cache
*
* @param name * @param name
* @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants) * @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants)
* @param reader * @param reader
@ -199,6 +202,7 @@ public class TagManager {
/** /**
* Loads a tag with the given name. This method reads from 'reader'. This will override the previous tag * Loads a tag with the given name. This method reads from 'reader'. This will override the previous tag
*
* @param name * @param name
* @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants) * @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants)
* @param readerSupplier * @param readerSupplier
@ -213,6 +217,7 @@ public class TagManager {
/** /**
* Loads a tag with the given name. This method attempts to read from 'reader' if the given name is not already present in cache * Loads a tag with the given name. This method attempts to read from 'reader' if the given name is not already present in cache
*
* @param name * @param name
* @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants) * @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants)
* @param readerSupplier * @param readerSupplier
@ -240,10 +245,11 @@ public class TagManager {
/** /**
* Adds the required tags for the game to function correctly * Adds the required tags for the game to function correctly
*
* @param tags the packet to add the tags to * @param tags the packet to add the tags to
*/ */
public void addRequiredTagsToPacket(TagsPacket tags) { public void addRequiredTagsToPacket(TagsPacket tags) {
for(RequiredTag requiredTag : requiredTags) { for (RequiredTag requiredTag : requiredTags) {
Tag tag = silentLoad(requiredTag.getName(), requiredTag.getType().name().toLowerCase()); Tag tag = silentLoad(requiredTag.getName(), requiredTag.getType().name().toLowerCase());
switch (requiredTag.getType()) { switch (requiredTag.getType()) {
case BLOCKS: case BLOCKS:
@ -267,6 +273,7 @@ public class TagManager {
/** /**
* Adds a required tag to send to players when they connect * Adds a required tag to send to players when they connect
*
* @param type type of tag to send. Required so the client knows its use * @param type type of tag to send. Required so the client knows its use
* @param name the name of the tag to load * @param name the name of the tag to load
*/ */

View File

@ -30,7 +30,7 @@ public interface IChunkLoader {
/** /**
* Does this ChunkLoader allow for multi-threaded saving of chunks? * Does this ChunkLoader allow for multi-threaded saving of chunks?
* *
* @return * @return true if the chunk loader supports parallel saving
*/ */
default boolean supportsParallelSaving() { default boolean supportsParallelSaving() {
return false; return false;
@ -39,7 +39,7 @@ public interface IChunkLoader {
/** /**
* Does this ChunkLoader allow for multi-threaded loading of chunks? * Does this ChunkLoader allow for multi-threaded loading of chunks?
* *
* @return * @return true if the chunk loader supports parallel loading
*/ */
default boolean supportsParallelLoading() { default boolean supportsParallelLoading() {
return false; return false;

View File

@ -919,10 +919,10 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
* Creates an explosion at the given position with the given strength. * Creates an explosion at the given position with the given strength.
* The algorithm used to compute damages is provided by {@link #getExplosionSupplier()}. * The algorithm used to compute damages is provided by {@link #getExplosionSupplier()}.
* *
* @param centerX * @param centerX the center X
* @param centerY * @param centerY the center Y
* @param centerZ * @param centerZ the center Z
* @param strength * @param strength the strength of the explosion
* @throws IllegalStateException If no {@link ExplosionSupplier} was supplied * @throws IllegalStateException If no {@link ExplosionSupplier} was supplied
*/ */
public void explode(float centerX, float centerY, float centerZ, float strength) { public void explode(float centerX, float centerY, float centerZ, float strength) {

View File

@ -142,8 +142,8 @@ public class InstanceContainer extends Instance {
/** /**
* Has this block already changed since last update? Prevents StackOverflow with blocks trying to modify their position in onDestroy or onPlace * Has this block already changed since last update? Prevents StackOverflow with blocks trying to modify their position in onDestroy or onPlace
* *
* @param blockPosition * @param blockPosition the block position
* @param blockId * @param blockId the block id
* @return * @return
*/ */
private boolean isAlreadyChanged(BlockPosition blockPosition, short blockId) { private boolean isAlreadyChanged(BlockPosition blockPosition, short blockId) {

View File

@ -129,7 +129,7 @@ public abstract class CustomBlock {
/** /**
* Defines custom behaviour for entities touching this block. * Defines custom behaviour for entities touching this block.
* *
* @param instance * @param instance the instance
* @param position the position at which the block is * @param position the position at which the block is
* @param touching the entity currently touching the block * @param touching the entity currently touching the block
*/ */
@ -220,7 +220,7 @@ public abstract class CustomBlock {
/** /**
* Called when an explosion wants to destroy this block. * Called when an explosion wants to destroy this block.
* *
* @param instance * @param instance the instance
* @param lootTableArguments arguments used in the loot table loot generation * @param lootTableArguments arguments used in the loot table loot generation
* @return 'true' if the explosion should happen on this block, 'false' to cancel the destruction. * @return 'true' if the explosion should happen on this block, 'false' to cancel the destruction.
* Returning true does NOT block the explosion rays, ie it does not change the block explosion resistance * Returning true does NOT block the explosion rays, ie it does not change the block explosion resistance
@ -232,7 +232,7 @@ public abstract class CustomBlock {
/** /**
* Return the loot table associated to this block. Return null to use vanilla behavior * Return the loot table associated to this block. Return null to use vanilla behavior
* *
* @param tableManager * @param tableManager the loot table manager
* @return the loot table associated to this block * @return the loot table associated to this block
*/ */
public LootTable getLootTable(LootTableManager tableManager) { public LootTable getLootTable(LootTableManager tableManager) {

View File

@ -66,8 +66,8 @@ public class StorageManager {
/** /**
* Used to know if the specified folder already exist or not * Used to know if the specified folder already exist or not
* *
* @param folderPath * @param folderPath the folder path
* @param storageSystem * @param storageSystem the storage system to use
* @return true if the folder exists, false otherwise * @return true if the folder exists, false otherwise
*/ */
public boolean folderExists(String folderPath, StorageSystem storageSystem) { public boolean folderExists(String folderPath, StorageSystem storageSystem) {
@ -77,8 +77,8 @@ public class StorageManager {
/** /**
* Call {@link #folderExists(String, StorageSystem)} with the default StorageSystem * Call {@link #folderExists(String, StorageSystem)} with the default StorageSystem
* *
* @param folderPath * @param folderPath the folder path
* @return * @return true if the folder exists
*/ */
public boolean folderExists(String folderPath) { public boolean folderExists(String folderPath) {
return folderExists(folderPath, defaultStorageSystemSupplier.get()); return folderExists(folderPath, defaultStorageSystemSupplier.get());
@ -93,6 +93,11 @@ public class StorageManager {
return Collections.unmodifiableCollection(folderMap.values()); return Collections.unmodifiableCollection(folderMap.values());
} }
/**
* Define the default storage system used for {@link StorageFolder}
*
* @param storageSystemSupplier the supplier called to get the default {@link StorageSystem}
*/
public void defineDefaultStorageSystem(Supplier<StorageSystem> storageSystemSupplier) { public void defineDefaultStorageSystem(Supplier<StorageSystem> storageSystemSupplier) {
if (this.defaultStorageSystemSupplier != null) { if (this.defaultStorageSystemSupplier != null) {
LOGGER.warn("The default storage-system has been changed. This could lead to issues!"); LOGGER.warn("The default storage-system has been changed. This could lead to issues!");
@ -100,6 +105,11 @@ public class StorageManager {
this.defaultStorageSystemSupplier = storageSystemSupplier; this.defaultStorageSystemSupplier = storageSystemSupplier;
} }
/**
* Get if the default storage system is set
*
* @return true if a default storage system is set
*/
public boolean isDefaultStorageSystemDefined() { public boolean isDefaultStorageSystemDefined() {
return defaultStorageSystemSupplier != null; return defaultStorageSystemSupplier != null;
} }

View File

@ -1,10 +1,16 @@
package net.minestom.server.storage; package net.minestom.server.storage;
/**
* Represent a way of storing data
* It works by using keys and values assigned to each one
*/
public interface StorageSystem { public interface StorageSystem {
/** /**
* @param folderPath * Get if the folder exists
* @return true if the folder exists, false otherwise *
* @param folderPath the folder path
* @return true if the folder exists
*/ */
boolean exists(String folderPath); boolean exists(String folderPath);
@ -17,7 +23,9 @@ public interface StorageSystem {
void open(String folderPath, StorageOptions storageOptions); void open(String folderPath, StorageOptions storageOptions);
/** /**
* @param key * Get the data associated to a key
*
* @param key the key to retrieve
* @return the retrieved data * @return the retrieved data
*/ */
byte[] get(String key); byte[] get(String key);
@ -25,15 +33,15 @@ public interface StorageSystem {
/** /**
* Set the specified data to the defined key * Set the specified data to the defined key
* *
* @param key * @param key the key of the data
* @param data * @param data the data
*/ */
void set(String key, byte[] data); void set(String key, byte[] data);
/** /**
* Delete the specified key from the database * Delete the specified key from the database
* *
* @param key * @param key the key to delete
*/ */
void delete(String key); void delete(String key);

View File

@ -25,7 +25,6 @@ public class PerGroupChunkProvider extends ThreadProvider {
@Override @Override
public void onChunkLoad(Instance instance, int chunkX, int chunkZ) { public void onChunkLoad(Instance instance, int chunkX, int chunkZ) {
Map<ChunkCoordinate, Set<ChunkCoordinate>> chunksGroupMap = getChunksGroupMap(instance); Map<ChunkCoordinate, Set<ChunkCoordinate>> chunksGroupMap = getChunksGroupMap(instance);
Map<Set<ChunkCoordinate>, Instance> instanceMap = getInstanceMap(instance); Map<Set<ChunkCoordinate>, Instance> instanceMap = getInstanceMap(instance);
@ -56,10 +55,13 @@ public class PerGroupChunkProvider extends ThreadProvider {
return; return;
} }
// Represent the merged group of all the neighbours
Set<ChunkCoordinate> finalGroup = new HashSet<>(); Set<ChunkCoordinate> finalGroup = new HashSet<>();
// Add the newly loaded chunk to the group
finalGroup.add(new ChunkCoordinate(chunkX, chunkZ)); finalGroup.add(new ChunkCoordinate(chunkX, chunkZ));
// Add all the neighbours groups to the final one
for (Set<ChunkCoordinate> chunkCoordinates : neighboursGroups) { for (Set<ChunkCoordinate> chunkCoordinates : neighboursGroups) {
finalGroup.addAll(chunkCoordinates); finalGroup.addAll(chunkCoordinates);
} }
@ -80,11 +82,13 @@ public class PerGroupChunkProvider extends ThreadProvider {
final ChunkCoordinate chunkCoordinate = new ChunkCoordinate(chunkX, chunkZ); final ChunkCoordinate chunkCoordinate = new ChunkCoordinate(chunkX, chunkZ);
if (chunksGroupMap.containsKey(chunkCoordinate)) { if (chunksGroupMap.containsKey(chunkCoordinate)) {
// The unloaded chunk is part of a group, remove it from the group
Set<ChunkCoordinate> chunkCoordinates = chunksGroupMap.get(chunkCoordinate); Set<ChunkCoordinate> chunkCoordinates = chunksGroupMap.get(chunkCoordinate);
chunkCoordinates.remove(chunkCoordinate); chunkCoordinates.remove(chunkCoordinate);
chunksGroupMap.remove(chunkCoordinate); chunksGroupMap.remove(chunkCoordinate);
if (chunkCoordinates.isEmpty()) { if (chunkCoordinates.isEmpty()) {
// The chunk group is empty, remove it entirely
instanceMap.entrySet().removeIf(entry -> entry.getKey().isEmpty()); instanceMap.entrySet().removeIf(entry -> entry.getKey().isEmpty());
} }
} }
@ -92,20 +96,20 @@ public class PerGroupChunkProvider extends ThreadProvider {
@Override @Override
public void update(long time) { public void update(long time) {
// Set of already-updated instances // Set of already-updated instances this tick
final Set<Instance> updatedInstance = new HashSet<>(); final Set<Instance> updatedInstance = new HashSet<>();
instanceInstanceMap.entrySet().forEach(entry -> { instanceInstanceMap.entrySet().forEach(entry -> {
final Instance instance = entry.getKey(); final Instance instance = entry.getKey();
final Map<Set<ChunkCoordinate>, Instance> instanceMap = entry.getValue(); final Map<Set<ChunkCoordinate>, Instance> instanceMap = entry.getValue();
// Update all the chunks // Update all the chunks + instances
for (Map.Entry<Set<ChunkCoordinate>, Instance> ent : instanceMap.entrySet()) { for (Map.Entry<Set<ChunkCoordinate>, Instance> ent : instanceMap.entrySet()) {
final Set<ChunkCoordinate> chunks = ent.getKey(); final Set<ChunkCoordinate> chunks = ent.getKey();
final boolean updateInstance = updatedInstance.add(instance); final boolean updateInstance = updatedInstance.add(instance);
pool.execute(() -> { pool.execute(() -> {
// Used to check if the instance has already been updated this tick
if (updateInstance) { if (updateInstance) {
updateInstance(instance, time); updateInstance(instance, time);
} }
@ -127,6 +131,14 @@ public class PerGroupChunkProvider extends ThreadProvider {
}); });
} }
/**
* Get all the neighbours of a chunk and itself, no diagonals
*
* @param instance the instance of the chunks
* @param chunkX the chunk X
* @param chunkZ the chunk Z
* @return the loaded neighbours of the chunk
*/
private List<ChunkCoordinate> getNeighbours(Instance instance, int chunkX, int chunkZ) { private List<ChunkCoordinate> getNeighbours(Instance instance, int chunkX, int chunkZ) {
List<ChunkCoordinate> chunks = new ArrayList<>(); List<ChunkCoordinate> chunks = new ArrayList<>();
// Constants used to loop through the neighbors // Constants used to loop through the neighbors
@ -144,9 +156,8 @@ public class PerGroupChunkProvider extends ThreadProvider {
final int targetZ = chunkZ + z; final int targetZ = chunkZ + z;
final Chunk chunk = instance.getChunk(targetX, targetZ); final Chunk chunk = instance.getChunk(targetX, targetZ);
if (!ChunkUtils.isChunkUnloaded(chunk)) { if (!ChunkUtils.isChunkUnloaded(chunk)) {
// Chunk is loaded, add it
chunks.add(toChunkCoordinate(chunk)); chunks.add(toChunkCoordinate(chunk));
} else {
//System.out.println(targetX+" : "+targetZ);
} }
} }

View File

@ -18,6 +18,7 @@ public class PerInstanceThreadProvider extends ThreadProvider {
@Override @Override
public void onChunkLoad(Instance instance, int chunkX, int chunkZ) { public void onChunkLoad(Instance instance, int chunkX, int chunkZ) {
// Add the loaded chunk to the instance chunks list
Set<ChunkCoordinate> chunkCoordinates = getChunkCoordinates(instance); Set<ChunkCoordinate> chunkCoordinates = getChunkCoordinates(instance);
chunkCoordinates.add(new ChunkCoordinate(chunkX, chunkZ)); chunkCoordinates.add(new ChunkCoordinate(chunkX, chunkZ));
} }
@ -25,7 +26,7 @@ public class PerInstanceThreadProvider extends ThreadProvider {
@Override @Override
public void onChunkUnload(Instance instance, int chunkX, int chunkZ) { public void onChunkUnload(Instance instance, int chunkX, int chunkZ) {
Set<ChunkCoordinate> chunkCoordinates = getChunkCoordinates(instance); Set<ChunkCoordinate> chunkCoordinates = getChunkCoordinates(instance);
// Remove the unloaded chunk from the instance list
chunkCoordinates.removeIf(chunkCoordinate -> chunkCoordinate.chunkX == chunkX && chunkCoordinates.removeIf(chunkCoordinate -> chunkCoordinate.chunkX == chunkX &&
chunkCoordinate.chunkZ == chunkZ); chunkCoordinate.chunkZ == chunkZ);

View File

@ -183,10 +183,20 @@ public abstract class ThreadProvider {
} }
} }
/**
* Convert a {@link Chunk} to a {@link ChunkCoordinate}
*
* @param chunk the chunk to convert
* @return the converted {@link ChunkCoordinate}
*/
protected ChunkCoordinate toChunkCoordinate(Chunk chunk) { protected ChunkCoordinate toChunkCoordinate(Chunk chunk) {
return new ChunkCoordinate(chunk.getChunkX(), chunk.getChunkZ()); return new ChunkCoordinate(chunk.getChunkX(), chunk.getChunkZ());
} }
/**
* Represent the coordinates of a {@link Chunk}
* Used so the chunks objects can be cleared by the garbage collector properly¬
*/
protected static class ChunkCoordinate { protected static class ChunkCoordinate {
public int chunkX, chunkZ; public int chunkX, chunkZ;

View File

@ -26,8 +26,10 @@ public class ArrayUtils {
} }
/** /**
* @param a * Get the differences between 2 arrays
* @param b *
* @param a the first array
* @param b the second array
* @return an array containing a's indexes that aren't in b array * @return an array containing a's indexes that aren't in b array
*/ */
public static int[] getDifferencesBetweenArray(long[] a, long[] b) { public static int[] getDifferencesBetweenArray(long[] a, long[] b) {

View File

@ -33,8 +33,8 @@ public class NBTUtils {
/** /**
* Loads all the items from the 'items' list into the given inventory * Loads all the items from the 'items' list into the given inventory
* *
* @param items * @param items the items to save
* @param destination * @param destination the inventory destination
*/ */
public static void loadAllItems(NBTList<NBTCompound> items, Inventory destination) { public static void loadAllItems(NBTList<NBTCompound> items, Inventory destination) {
destination.clear(); destination.clear();

View File

@ -36,7 +36,7 @@ public class WeightedRandom<E extends WeightedRandomItem> {
* Gets a random element from this set * Gets a random element from this set
* *
* @param rng Random Number Generator to generate random numbers with * @param rng Random Number Generator to generate random numbers with
* @return * @return a random element from this set
*/ */
public E get(Random rng) { public E get(Random rng) {
final double p = rng.nextDouble() * totalWeight; final double p = rng.nextDouble() * totalWeight;