mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-11-26 20:45:16 +01:00
Add forge live-implementation, improve fabric implementation and fix possible CME
This commit is contained in:
parent
59c3f8adc5
commit
e72fb4f21a
@ -72,7 +72,7 @@ public synchronized void removeAllListeners() {
|
|||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
public synchronized void onWorldSaveToDisk(WorldSaveEvent evt) {
|
public synchronized void onWorldSaveToDisk(WorldSaveEvent evt) {
|
||||||
listeners.forEach(l -> l.onWorldSaveToDisk(evt.getWorld().getUID()));
|
for (ServerEventListener listener : listeners) listener.onWorldSaveToDisk(evt.getWorld().getUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
@ -123,7 +123,7 @@ public void onBlockChange(BlockFertilizeEvent evt) {
|
|||||||
private synchronized void onBlockChange(Location loc) {
|
private synchronized void onBlockChange(Location loc) {
|
||||||
UUID world = loc.getWorld().getUID();
|
UUID world = loc.getWorld().getUID();
|
||||||
Vector3i pos = new Vector3i(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
Vector3i pos = new Vector3i(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||||
listeners.forEach(l -> l.onBlockChange(world, pos));
|
for (ServerEventListener listener : listeners) listener.onBlockChange(world, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
@ -131,23 +131,23 @@ public synchronized void onChunkFinishedGeneration(ChunkPopulateEvent evt) {
|
|||||||
Chunk chunk = evt.getChunk();
|
Chunk chunk = evt.getChunk();
|
||||||
UUID world = chunk.getWorld().getUID();
|
UUID world = chunk.getWorld().getUID();
|
||||||
Vector2i chunkPos = new Vector2i(chunk.getX(), chunk.getZ());
|
Vector2i chunkPos = new Vector2i(chunk.getX(), chunk.getZ());
|
||||||
listeners.forEach(l -> l.onChunkFinishedGeneration(world, chunkPos));
|
for (ServerEventListener listener : listeners) listener.onChunkFinishedGeneration(world, chunkPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
public void onPlayerJoin(PlayerJoinEvent evt) {
|
public synchronized void onPlayerJoin(PlayerJoinEvent evt) {
|
||||||
listeners.forEach(l -> l.onPlayerJoin(evt.getPlayer().getUniqueId()));
|
for (ServerEventListener listener : listeners) listener.onPlayerJoin(evt.getPlayer().getUniqueId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
public void onPlayerLeave(PlayerQuitEvent evt) {
|
public synchronized void onPlayerLeave(PlayerQuitEvent evt) {
|
||||||
listeners.forEach(l -> l.onPlayerJoin(evt.getPlayer().getUniqueId()));
|
for (ServerEventListener listener : listeners) listener.onPlayerJoin(evt.getPlayer().getUniqueId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
public void onPlayerChat(AsyncPlayerChatEvent evt) {
|
public synchronized void onPlayerChat(AsyncPlayerChatEvent evt) {
|
||||||
String message = String.format(evt.getFormat(), evt.getPlayer().getDisplayName(), evt.getMessage());
|
String message = String.format(evt.getFormat(), evt.getPlayer().getDisplayName(), evt.getMessage());
|
||||||
listeners.forEach(l -> l.onChatMessage(Text.of(message)));
|
for (ServerEventListener listener : listeners) listener.onChatMessage(Text.of(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -69,11 +69,11 @@ public FabricEventForwarder(FabricMod mod) {
|
|||||||
PlayerLeaveCallback.EVENT.register(this::onPlayerLeave);
|
PlayerLeaveCallback.EVENT.register(this::onPlayerLeave);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEventListener(ServerEventListener listener) {
|
public synchronized void addEventListener(ServerEventListener listener) {
|
||||||
this.eventListeners.add(listener);
|
this.eventListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeAllListeners() {
|
public synchronized void removeAllListeners() {
|
||||||
this.eventListeners.clear();
|
this.eventListeners.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,45 +94,47 @@ public ActionResult onBlockAttack(PlayerEntity player, World world, Hand hand, B
|
|||||||
return ActionResult.PASS;
|
return ActionResult.PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBlockChange(ServerWorld world, BlockPos blockPos) {
|
public synchronized void onBlockChange(ServerWorld world, BlockPos blockPos) {
|
||||||
Vector3i position = new Vector3i(blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
Vector3i position = new Vector3i(blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
UUID uuid = mod.getUUIDForWorld(world);
|
UUID uuid = mod.getUUIDForWorld(world);
|
||||||
eventListeners.forEach(e -> e.onBlockChange(uuid, position));
|
for (ServerEventListener listener : eventListeners) listener.onBlockChange(uuid, position);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Logger.global.logError("Failed to get UUID for world: " + world, e);
|
Logger.global.noFloodError("Failed to get the UUID for a world!", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onWorldSave(ServerWorld world) {
|
public synchronized void onWorldSave(ServerWorld world) {
|
||||||
try {
|
try {
|
||||||
UUID uuid = mod.getUUIDForWorld(world);
|
UUID uuid = mod.getUUIDForWorld(world);
|
||||||
eventListeners.forEach(e -> e.onWorldSaveToDisk(uuid));
|
for (ServerEventListener listener : eventListeners) listener.onWorldSaveToDisk(uuid);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Logger.global.logError("Failed to get UUID for world: " + world, e);
|
Logger.global.noFloodError("Failed to get the UUID for a world!", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onChunkFinalize(ServerWorld world, Vector2i chunkPos) {
|
public synchronized void onChunkFinalize(ServerWorld world, Vector2i chunkPos) {
|
||||||
try {
|
try {
|
||||||
UUID uuid = mod.getUUIDForWorld(world);
|
UUID uuid = mod.getUUIDForWorld(world);
|
||||||
eventListeners.forEach(e -> e.onChunkFinishedGeneration(uuid, chunkPos));
|
for (ServerEventListener listener : eventListeners) listener.onChunkFinishedGeneration(uuid, chunkPos);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Logger.global.logError("Failed to get UUID for world: " + world, e);
|
Logger.global.noFloodError("Failed to get the UUID for a world!", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPlayerJoin(MinecraftServer server, ServerPlayerEntity player) {
|
public synchronized void onPlayerJoin(MinecraftServer server, ServerPlayerEntity player) {
|
||||||
if (this.mod.getServer() != server) return;
|
if (this.mod.getServer() != server) return;
|
||||||
|
|
||||||
this.eventListeners.forEach(l -> l.onPlayerJoin(player.getUuid()));
|
UUID uuid = player.getUuid();
|
||||||
|
for (ServerEventListener listener : eventListeners) listener.onPlayerJoin(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPlayerLeave(MinecraftServer server, ServerPlayerEntity player) {
|
public synchronized void onPlayerLeave(MinecraftServer server, ServerPlayerEntity player) {
|
||||||
if (this.mod.getServer() != server) return;
|
if (this.mod.getServer() != server) return;
|
||||||
|
|
||||||
this.eventListeners.forEach(l -> l.onPlayerLeave(player.getUuid()));
|
UUID uuid = player.getUuid();
|
||||||
|
for (ServerEventListener listener : eventListeners) listener.onPlayerLeave(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ public class FabricMod implements ModInitializer, ServerInterface {
|
|||||||
private Plugin pluginInstance = null;
|
private Plugin pluginInstance = null;
|
||||||
private MinecraftServer serverInstance = null;
|
private MinecraftServer serverInstance = null;
|
||||||
|
|
||||||
private Map<File, UUID> worldUuids;
|
private Map<File, UUID> worldUUIDs;
|
||||||
private FabricEventForwarder eventForwarder;
|
private FabricEventForwarder eventForwarder;
|
||||||
|
|
||||||
private LoadingCache<ServerWorld, UUID> worldUuidCache;
|
private LoadingCache<ServerWorld, UUID> worldUuidCache;
|
||||||
@ -82,7 +82,7 @@ public FabricMod() {
|
|||||||
|
|
||||||
pluginInstance = new Plugin("fabric", this);
|
pluginInstance = new Plugin("fabric", this);
|
||||||
|
|
||||||
this.worldUuids = new ConcurrentHashMap<>();
|
this.worldUUIDs = new ConcurrentHashMap<>();
|
||||||
this.eventForwarder = new FabricEventForwarder(this);
|
this.eventForwarder = new FabricEventForwarder(this);
|
||||||
this.worldUuidCache = CacheBuilder.newBuilder()
|
this.worldUuidCache = CacheBuilder.newBuilder()
|
||||||
.weakKeys()
|
.weakKeys()
|
||||||
@ -111,7 +111,7 @@ public void onInitialize() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
pluginInstance.load();
|
pluginInstance.load();
|
||||||
Logger.global.logInfo("BlueMap loaded!");
|
if (pluginInstance.isLoaded()) Logger.global.logInfo("BlueMap loaded!");
|
||||||
} catch (IOException | ParseResourceException e) {
|
} catch (IOException | ParseResourceException e) {
|
||||||
Logger.global.logError("Failed to load bluemap!", e);
|
Logger.global.logError("Failed to load bluemap!", e);
|
||||||
}
|
}
|
||||||
@ -145,10 +145,10 @@ public void unregisterAllListeners() {
|
|||||||
public UUID getUUIDForWorld(File worldFolder) throws IOException {
|
public UUID getUUIDForWorld(File worldFolder) throws IOException {
|
||||||
worldFolder = worldFolder.getCanonicalFile();
|
worldFolder = worldFolder.getCanonicalFile();
|
||||||
|
|
||||||
UUID uuid = worldUuids.get(worldFolder);
|
UUID uuid = worldUUIDs.get(worldFolder);
|
||||||
if (uuid == null) {
|
if (uuid == null) {
|
||||||
uuid = UUID.randomUUID();
|
uuid = UUID.randomUUID();
|
||||||
worldUuids.put(worldFolder, uuid);
|
worldUUIDs.put(worldFolder, uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return uuid;
|
return uuid;
|
||||||
|
@ -52,6 +52,7 @@ public class FabricPlayer implements Player {
|
|||||||
GAMEMODE_MAP.put(GameMode.SURVIVAL, Gamemode.SURVIVAL);
|
GAMEMODE_MAP.put(GameMode.SURVIVAL, Gamemode.SURVIVAL);
|
||||||
GAMEMODE_MAP.put(GameMode.CREATIVE, Gamemode.CREATIVE);
|
GAMEMODE_MAP.put(GameMode.CREATIVE, Gamemode.CREATIVE);
|
||||||
GAMEMODE_MAP.put(GameMode.SPECTATOR, Gamemode.SPECTATOR);
|
GAMEMODE_MAP.put(GameMode.SPECTATOR, Gamemode.SPECTATOR);
|
||||||
|
GAMEMODE_MAP.put(GameMode.NOT_SET, Gamemode.SURVIVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
@ -115,7 +116,7 @@ public Gamemode getGamemode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API access, only call on server thread!
|
* Only call on server thread!
|
||||||
*/
|
*/
|
||||||
public void update() {
|
public void update() {
|
||||||
ServerPlayerEntity player = delegate.get();
|
ServerPlayerEntity player = delegate.get();
|
||||||
@ -139,7 +140,7 @@ public void update() {
|
|||||||
this.invisible = invis != null && invis.getDuration() > 0;
|
this.invisible = invis != null && invis.getDuration() > 0;
|
||||||
|
|
||||||
this.name = Text.of(player.getName().getString());
|
this.name = Text.of(player.getName().getString());
|
||||||
this.online = !player.removed;
|
this.online = true;
|
||||||
|
|
||||||
Vec3d pos = player.getPos();
|
Vec3d pos = player.getPos();
|
||||||
this.position = new Vector3d(pos.getX(), pos.getY(), pos.getZ());
|
this.position = new Vector3d(pos.getX(), pos.getY(), pos.getZ());
|
||||||
|
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package de.bluecolored.bluemap.forge;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.flowpowered.math.vector.Vector3i;
|
||||||
|
|
||||||
|
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerEventListener;
|
||||||
|
import de.bluecolored.bluemap.core.logger.Logger;
|
||||||
|
import net.minecraft.world.server.ServerWorld;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedInEvent;
|
||||||
|
import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedOutEvent;
|
||||||
|
import net.minecraftforge.event.world.BlockEvent;
|
||||||
|
import net.minecraftforge.event.world.WorldEvent;
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
|
||||||
|
public class ForgeEventForwarder {
|
||||||
|
|
||||||
|
private ForgeMod mod;
|
||||||
|
private Collection<ServerEventListener> eventListeners;
|
||||||
|
|
||||||
|
public ForgeEventForwarder(ForgeMod mod) {
|
||||||
|
this.mod = mod;
|
||||||
|
this.eventListeners = new ArrayList<>(1);
|
||||||
|
|
||||||
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void addEventListener(ServerEventListener listener) {
|
||||||
|
this.eventListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void removeAllListeners() {
|
||||||
|
this.eventListeners.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onBlockBreak(BlockEvent.BreakEvent evt) {
|
||||||
|
onBlockChange(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onBlockPlace(BlockEvent.EntityPlaceEvent evt) {
|
||||||
|
onBlockChange(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void onBlockChange(BlockEvent evt) {
|
||||||
|
if (!(evt.getWorld() instanceof ServerWorld)) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
UUID world = mod.getUUIDForWorld((ServerWorld) evt.getWorld());
|
||||||
|
Vector3i position = new Vector3i(
|
||||||
|
evt.getPos().getX(),
|
||||||
|
evt.getPos().getY(),
|
||||||
|
evt.getPos().getZ()
|
||||||
|
);
|
||||||
|
|
||||||
|
for (ServerEventListener listener : eventListeners) listener.onBlockChange(world, position);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
Logger.global.noFloodError("Failed to get the UUID for a world!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public synchronized void onWorldSave(WorldEvent.Save evt) {
|
||||||
|
if (!(evt.getWorld() instanceof ServerWorld)) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
UUID world = mod.getUUIDForWorld((ServerWorld) evt.getWorld());
|
||||||
|
for (ServerEventListener listener : eventListeners) listener.onWorldSaveToDisk(world);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Logger.global.noFloodError("Failed to get the UUID for a world!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public synchronized void onPlayerJoin(PlayerLoggedInEvent evt) {
|
||||||
|
UUID uuid = evt.getPlayer().getUniqueID();
|
||||||
|
for (ServerEventListener listener : eventListeners) listener.onPlayerJoin(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public synchronized void onPlayerLeave(PlayerLoggedOutEvent evt) {
|
||||||
|
UUID uuid = evt.getPlayer().getUniqueID();
|
||||||
|
for (ServerEventListener listener : eventListeners) listener.onPlayerLeave(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -29,15 +29,15 @@
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
|
||||||
import com.flowpowered.math.vector.Vector3i;
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.cache.CacheLoader;
|
import com.google.common.cache.CacheLoader;
|
||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
@ -48,11 +48,15 @@
|
|||||||
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerEventListener;
|
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerEventListener;
|
||||||
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerInterface;
|
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerInterface;
|
||||||
import de.bluecolored.bluemap.core.logger.Logger;
|
import de.bluecolored.bluemap.core.logger.Logger;
|
||||||
import net.minecraft.command.CommandSource;
|
import de.bluecolored.bluemap.core.resourcepack.ParseResourceException;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.world.server.ServerWorld;
|
import net.minecraft.world.server.ServerWorld;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.event.world.BlockEvent;
|
import net.minecraftforge.event.TickEvent.ServerTickEvent;
|
||||||
import net.minecraftforge.event.world.WorldEvent;
|
import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedInEvent;
|
||||||
|
import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedOutEvent;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
|
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
|
||||||
@ -60,20 +64,29 @@
|
|||||||
|
|
||||||
@Mod(Plugin.PLUGIN_ID)
|
@Mod(Plugin.PLUGIN_ID)
|
||||||
public class ForgeMod implements ServerInterface {
|
public class ForgeMod implements ServerInterface {
|
||||||
|
|
||||||
|
private Plugin pluginInstance = null;
|
||||||
|
private MinecraftServer serverInstance = null;
|
||||||
|
|
||||||
private Plugin bluemap;
|
private Map<File, UUID> worldUUIDs;
|
||||||
private Commands<CommandSource> commands;
|
private ForgeEventForwarder eventForwarder;
|
||||||
private Map<String, UUID> worldUUIDs;
|
|
||||||
private Collection<ServerEventListener> eventListeners;
|
|
||||||
|
|
||||||
private LoadingCache<ServerWorld, UUID> worldUuidCache;
|
private LoadingCache<ServerWorld, UUID> worldUuidCache;
|
||||||
|
|
||||||
|
private int playerUpdateIndex = 0;
|
||||||
|
private Map<UUID, Player> onlinePlayerMap;
|
||||||
|
private List<ForgePlayer> onlinePlayerList;
|
||||||
|
|
||||||
public ForgeMod() {
|
public ForgeMod() {
|
||||||
Logger.global = new Log4jLogger(LogManager.getLogger(Plugin.PLUGIN_NAME));
|
Logger.global = new Log4jLogger(LogManager.getLogger(Plugin.PLUGIN_NAME));
|
||||||
|
|
||||||
this.bluemap = new Plugin("forge", this);
|
this.onlinePlayerMap = new ConcurrentHashMap<>();
|
||||||
this.worldUUIDs = new HashMap<>();
|
this.onlinePlayerList = Collections.synchronizedList(new ArrayList<>());
|
||||||
this.eventListeners = new ArrayList<>(1);
|
|
||||||
|
this.pluginInstance = new Plugin("forge", this);
|
||||||
|
|
||||||
|
this.worldUUIDs = new ConcurrentHashMap<>();
|
||||||
|
this.eventForwarder = new ForgeEventForwarder(this);
|
||||||
this.worldUuidCache = CacheBuilder.newBuilder()
|
this.worldUuidCache = CacheBuilder.newBuilder()
|
||||||
.weakKeys()
|
.weakKeys()
|
||||||
.maximumSize(1000)
|
.maximumSize(1000)
|
||||||
@ -83,113 +96,61 @@ public UUID load(ServerWorld key) throws Exception {
|
|||||||
return loadUUIDForWorld(key);
|
return loadUUIDForWorld(key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
MinecraftForge.EVENT_BUS.register(this);
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void onServerStarting(FMLServerStartingEvent event) {
|
public void onServerStarting(FMLServerStartingEvent event) {
|
||||||
this.worldUUIDs.clear();
|
this.worldUUIDs.clear();
|
||||||
|
|
||||||
for (ServerWorld world : event.getServer().getWorlds()) {
|
|
||||||
try {
|
|
||||||
registerWorld(world);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Logger.global.logError("Failed to register world: " + world.getProviderName(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
world.save(null, false, false);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
Logger.global.logError("Failed to save world: " + world.getProviderName(), t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//register commands
|
//register commands
|
||||||
this.commands = new Commands<>(bluemap, event.getCommandDispatcher(), forgeSource -> new ForgeCommandSource(this, bluemap, forgeSource));
|
new Commands<>(pluginInstance, event.getCommandDispatcher(), forgeSource -> new ForgeCommandSource(this, pluginInstance, forgeSource));
|
||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
|
Logger.global.logInfo("Loading...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Logger.global.logInfo("Loading...");
|
pluginInstance.load();
|
||||||
bluemap.load();
|
if (pluginInstance.isLoaded()) Logger.global.logInfo("Loaded!");
|
||||||
if (bluemap.isLoaded()) Logger.global.logInfo("Loaded!");
|
} catch (IOException | ParseResourceException e) {
|
||||||
} catch (Throwable t) {
|
Logger.global.logError("Failed to load bluemap!", e);
|
||||||
Logger.global.logError("Failed to load!", t);
|
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerWorld(ServerWorld world) throws IOException {
|
|
||||||
getUUIDForWorld(world);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void onServerStopping(FMLServerStoppingEvent event) {
|
public void onServerStopping(FMLServerStoppingEvent event) {
|
||||||
Logger.global.logInfo("Stopping...");
|
pluginInstance.unload();
|
||||||
bluemap.unload();
|
Logger.global.logInfo("BlueMap unloaded!");
|
||||||
Logger.global.logInfo("Saved and stopped!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onTick(ServerTickEvent evt) {
|
||||||
|
updateSomePlayers();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerListener(ServerEventListener listener) {
|
public void registerListener(ServerEventListener listener) {
|
||||||
eventListeners.add(listener);
|
eventForwarder.addEventListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unregisterAllListeners() {
|
public void unregisterAllListeners() {
|
||||||
eventListeners.clear();
|
eventForwarder.removeAllListeners();
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void onBlockBreak(BlockEvent.BreakEvent evt) {
|
|
||||||
onBlockChange(evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void onBlockPlace(BlockEvent.EntityPlaceEvent evt) {
|
|
||||||
onBlockChange(evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onBlockChange(BlockEvent evt) {
|
|
||||||
if (!(evt.getWorld() instanceof ServerWorld)) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
UUID world = getUUIDForWorld((ServerWorld) evt.getWorld());
|
|
||||||
Vector3i position = new Vector3i(
|
|
||||||
evt.getPos().getX(),
|
|
||||||
evt.getPos().getY(),
|
|
||||||
evt.getPos().getZ()
|
|
||||||
);
|
|
||||||
|
|
||||||
for (ServerEventListener listener : eventListeners) listener.onBlockChange(world, position);
|
|
||||||
|
|
||||||
} catch (IOException ignore) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void onWorldSave(WorldEvent.Save evt) {
|
|
||||||
if (!(evt.getWorld() instanceof ServerWorld)) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
UUID world = getUUIDForWorld((ServerWorld) evt.getWorld());
|
|
||||||
|
|
||||||
for (ServerEventListener listener : eventListeners) listener.onWorldSaveToDisk(world);
|
|
||||||
|
|
||||||
} catch (IOException ignore) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UUID getUUIDForWorld(File worldFolder) throws IOException {
|
public UUID getUUIDForWorld(File worldFolder) throws IOException {
|
||||||
synchronized (worldUUIDs) {
|
worldFolder = worldFolder.getCanonicalFile();
|
||||||
String key = worldFolder.getCanonicalPath();
|
|
||||||
|
UUID uuid = worldUUIDs.get(worldFolder);
|
||||||
UUID uuid = worldUUIDs.get(key);
|
if (uuid == null) {
|
||||||
if (uuid == null) {
|
uuid = UUID.randomUUID();
|
||||||
throw new IOException("There is no world with this folder loaded: " + worldFolder.getPath());
|
worldUUIDs.put(worldFolder, uuid);
|
||||||
}
|
|
||||||
|
|
||||||
return uuid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getUUIDForWorld(ServerWorld world) throws IOException {
|
public UUID getUUIDForWorld(ServerWorld world) throws IOException {
|
||||||
@ -203,17 +164,15 @@ public UUID getUUIDForWorld(ServerWorld world) throws IOException {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private UUID loadUUIDForWorld(ServerWorld world) throws IOException {
|
private UUID loadUUIDForWorld(ServerWorld world) throws IOException {
|
||||||
synchronized (worldUUIDs) {
|
File key = getFolderForWorld(world);
|
||||||
String key = getFolderForWorld(world).getPath();
|
|
||||||
|
UUID uuid = worldUUIDs.get(key);
|
||||||
UUID uuid = worldUUIDs.get(key);
|
if (uuid == null) {
|
||||||
if (uuid == null) {
|
uuid = UUID.randomUUID();
|
||||||
uuid = UUID.randomUUID();
|
worldUUIDs.put(key, uuid);
|
||||||
worldUUIDs.put(key, uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
return uuid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private File getFolderForWorld(ServerWorld world) throws IOException {
|
private File getFolderForWorld(ServerWorld world) throws IOException {
|
||||||
@ -231,21 +190,60 @@ private File getFolderForWorld(ServerWorld world) throws IOException {
|
|||||||
public File getConfigFolder() {
|
public File getConfigFolder() {
|
||||||
return new File("config/bluemap");
|
return new File("config/bluemap");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onPlayerJoin(PlayerLoggedInEvent evt) {
|
||||||
|
PlayerEntity playerInstance = evt.getPlayer();
|
||||||
|
if (!(playerInstance instanceof ServerPlayerEntity)) return;
|
||||||
|
|
||||||
|
ForgePlayer player = new ForgePlayer(this, (ServerPlayerEntity) playerInstance);
|
||||||
|
onlinePlayerMap.put(player.getUuid(), player);
|
||||||
|
onlinePlayerList.add(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPlayerLeave(PlayerLoggedOutEvent evt) {
|
||||||
|
PlayerEntity player = evt.getPlayer();
|
||||||
|
if (!(player instanceof ServerPlayerEntity)) return;
|
||||||
|
|
||||||
|
UUID playerUUID = player.getUniqueID();
|
||||||
|
onlinePlayerMap.remove(playerUUID);
|
||||||
|
synchronized (onlinePlayerList) {
|
||||||
|
onlinePlayerList.removeIf(p -> p.getUuid().equals(playerUUID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Commands<CommandSource> getCommands() {
|
public MinecraftServer getServer() {
|
||||||
return commands;
|
return this.serverInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Player> getOnlinePlayers() {
|
public Collection<Player> getOnlinePlayers() {
|
||||||
// TODO Implement
|
return onlinePlayerMap.values();
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Player> getPlayer(UUID uuid) {
|
public Optional<Player> getPlayer(UUID uuid) {
|
||||||
// TODO Implement
|
return Optional.ofNullable(onlinePlayerMap.get(uuid));
|
||||||
return Optional.empty();
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only update some of the online players each tick to minimize performance impact on the server-thread.
|
||||||
|
* Only call this method on the server-thread.
|
||||||
|
*/
|
||||||
|
private void updateSomePlayers() {
|
||||||
|
int onlinePlayerCount = onlinePlayerList.size();
|
||||||
|
if (onlinePlayerCount == 0) return;
|
||||||
|
|
||||||
|
int playersToBeUpdated = onlinePlayerCount / 20; //with 20 tps, each player is updated once a second
|
||||||
|
if (playersToBeUpdated == 0) playersToBeUpdated = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < playersToBeUpdated; i++) {
|
||||||
|
playerUpdateIndex++;
|
||||||
|
if (playerUpdateIndex >= 20 && playerUpdateIndex >= onlinePlayerCount) playerUpdateIndex = 0;
|
||||||
|
|
||||||
|
if (playerUpdateIndex < onlinePlayerCount) {
|
||||||
|
onlinePlayerList.get(i).update();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package de.bluecolored.bluemap.forge;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.flowpowered.math.vector.Vector3d;
|
||||||
|
|
||||||
|
import de.bluecolored.bluemap.common.plugin.serverinterface.Gamemode;
|
||||||
|
import de.bluecolored.bluemap.common.plugin.serverinterface.Player;
|
||||||
|
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||||
|
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||||
|
import net.minecraft.potion.EffectInstance;
|
||||||
|
import net.minecraft.potion.Effects;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.world.GameType;
|
||||||
|
|
||||||
|
public class ForgePlayer implements Player {
|
||||||
|
|
||||||
|
private static final UUID UNKNOWN_WORLD_UUID = UUID.randomUUID();
|
||||||
|
|
||||||
|
private static final Map<GameType, Gamemode> GAMEMODE_MAP = new EnumMap<>(GameType.class);
|
||||||
|
static {
|
||||||
|
GAMEMODE_MAP.put(GameType.ADVENTURE, Gamemode.ADVENTURE);
|
||||||
|
GAMEMODE_MAP.put(GameType.SURVIVAL, Gamemode.SURVIVAL);
|
||||||
|
GAMEMODE_MAP.put(GameType.CREATIVE, Gamemode.CREATIVE);
|
||||||
|
GAMEMODE_MAP.put(GameType.SPECTATOR, Gamemode.SPECTATOR);
|
||||||
|
GAMEMODE_MAP.put(GameType.NOT_SET, Gamemode.SURVIVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UUID uuid;
|
||||||
|
private Text name;
|
||||||
|
private UUID world;
|
||||||
|
private Vector3d position;
|
||||||
|
private boolean online;
|
||||||
|
private boolean sneaking;
|
||||||
|
private boolean invisible;
|
||||||
|
private Gamemode gamemode;
|
||||||
|
|
||||||
|
private ForgeMod mod;
|
||||||
|
private WeakReference<ServerPlayerEntity> delegate;
|
||||||
|
|
||||||
|
public ForgePlayer(ForgeMod mod, ServerPlayerEntity delegate) {
|
||||||
|
this.uuid = delegate.getUniqueID();
|
||||||
|
this.mod = mod;
|
||||||
|
this.delegate = new WeakReference<>(delegate);
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getUuid() {
|
||||||
|
return this.uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getWorld() {
|
||||||
|
return this.world;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector3d getPosition() {
|
||||||
|
return this.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOnline() {
|
||||||
|
return this.online;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSneaking() {
|
||||||
|
return this.sneaking;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInvisible() {
|
||||||
|
return this.invisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Gamemode getGamemode() {
|
||||||
|
return this.gamemode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only call on server thread!
|
||||||
|
*/
|
||||||
|
public void update() {
|
||||||
|
ServerPlayerEntity player = delegate.get();
|
||||||
|
if (player == null) {
|
||||||
|
MinecraftServer server = mod.getServer();
|
||||||
|
if (server != null) {
|
||||||
|
player = server.getPlayerList().getPlayerByUUID(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player == null) {
|
||||||
|
this.online = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate = new WeakReference<>(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.gamemode = GAMEMODE_MAP.get(player.interactionManager.getGameType());
|
||||||
|
|
||||||
|
EffectInstance invis = player.getActivePotionEffect(Effects.INVISIBILITY);
|
||||||
|
this.invisible = invis != null && invis.getDuration() > 0;
|
||||||
|
|
||||||
|
this.name = Text.of(player.getName().getString());
|
||||||
|
this.online = true;
|
||||||
|
|
||||||
|
Vec3d pos = player.getPositionVec();
|
||||||
|
this.position = new Vector3d(pos.getX(), pos.getY(), pos.getZ());
|
||||||
|
this.sneaking = player.isSneaking();
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.world = mod.getUUIDForWorld(player.getServerWorld());
|
||||||
|
} catch (IOException e) {
|
||||||
|
this.world = UNKNOWN_WORLD_UUID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user