1
0
Fork 0

Many Significant Changes

- Added:
  - QueueManager
  - GameManager
  - GameQueue
  - GameLobby
  - Server Settings
  - Basic NPC implementation
  - Randomized Elimination Messages
This commit is contained in:
Andus 2024-08-11 01:48:07 +02:00
parent 6c0da06eb5
commit 35514614eb
20 changed files with 503 additions and 36 deletions

1
.idea/gradle.xml generated
View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>

View file

@ -1,15 +1,21 @@
plugins {
id("java")
alias(libs.plugins.shadowJar)
}
group = "dev.celestialfox"
version = "1.0-SNAPSHOT"
version = "1.0"
repositories {
mavenCentral()
}
dependencies {
implementation("net.minestom:minestom-snapshots:461c56e749")
implementation("dev.hollowcube:polar:1.11.1")
implementation("net.kyori:adventure-text-minimessage:4.17.0")
implementation("org.slf4j:slf4j-api:2.0.13")
implementation("ch.qos.logback:logback-classic:1.5.6")
testImplementation(platform("org.junit:junit-bom:5.9.1"))
testImplementation("org.junit.jupiter:junit-jupiter")
}

View file

@ -1,9 +1,6 @@
metadata.format.version = "1.1"
[versions]
# Gradle plugins
blossom = "1.3.1"
shadowJar = "8.1.1"
[libraries]
@ -11,6 +8,4 @@ shadowJar = "8.1.1"
[bundles]
[plugins]
blossom = { id = "net.kyori.blossom", version.ref = "blossom" }
shadowJar = { id = "com.github.johnrengelman.shadow", version.ref = "shadowJar" }

4
server/config.properties Normal file
View file

@ -0,0 +1,4 @@
#Server Configuration
#Fri Aug 09 15:20:10 CEST 2024
server.ip=0.0.0.0
server.port=25565

View file

@ -1,34 +1,33 @@
package dev.celestialfox.gamejam;
package dev.cfox.gamejam;
import dev.celestialfox.gamejam.utils.Checks;
import dev.celestialfox.gamejam.utils.config.Settings;
import dev.celestialfox.gamejam.utils.events.StartEvents;
import dev.cfox.gamejam.utils.config.Checks;
import dev.cfox.gamejam.utils.config.Settings;
import dev.cfox.gamejam.utils.events.StartEvents;
import net.minestom.server.MinecraftServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
public class Server {
// Other
private static final Logger logger = LoggerFactory.getLogger(Server.class);
public static void main(String[] args) throws IOException {
public static void main(String[] args) {
// Server
logger.info("Initializing Server");
MinecraftServer minecraftServer = MinecraftServer.init();
MinecraftServer server = MinecraftServer.init();
// Files
Checks.worldFiles();
logger.info("File Checks (Config, Worlds)");
Checks.configFile();
Checks.worldFiles();
// Events
logger.info("Setting Up - Startup Events (Chat, Spawn, etc.)");
logger.info("Startup Events (Chat, Spawn, etc.)");
StartEvents.registerChat();
StartEvents.handleSpawn();
// Server Start
minecraftServer.start(Settings.getIP(), Settings.getPort());
logger.info("Server Started!");
server.start(Settings.getIP(), Settings.getPort());
logger.info("Server Started at " + Settings.getIP() + ":" + Settings.getPort() + " (MC: " + MinecraftServer.VERSION_NAME + ")");
}
}

View file

@ -0,0 +1,108 @@
package dev.cfox.gamejam.game.classes;
import dev.cfox.gamejam.game.managers.GameManager;
import dev.cfox.gamejam.utils.classes.Randomized;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance;
import net.minestom.server.network.packet.server.play.TeamsPacket;
import net.minestom.server.scoreboard.Team;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Objects;
import java.util.UUID;
public class GameLobby {
private static final Logger logger = LoggerFactory.getLogger(GameLobby.class);
private final ArrayList<UUID> players = new ArrayList<>();
Team team = MinecraftServer.getTeamManager().createTeam("team_" + getName());
private final ArrayList<UUID> eliminated = new ArrayList<>();
private final ArrayList<UUID> eliminatedThisRound = new ArrayList<>();
private Instance instance;
private String name = "";
public void setPlayers(ArrayList<UUID> playerList) {
players.addAll(playerList);
for (UUID uuid : players) {
team.addMember(MinecraftServer.getConnectionManager().getOnlinePlayerByUuid(uuid).getUsername());
}
team.updateCollisionRule(TeamsPacket.CollisionRule.NEVER);
}
public void eliminate(Player player) {
if (!eliminated.contains(player)) {
eliminated.add(player.getUuid());
eliminatedThisRound.add(player.getUuid());
logger.info("Player " + player.getUsername() + " got eliminated (GameLobby: " + name + ")");
sendMessage(Randomized.elimination(player));
player.sendMessage(Component.text("You've got eliminated!", NamedTextColor.RED, TextDecoration.BOLD));
player.setGameMode(GameMode.SPECTATOR);
}
}
public ArrayList<UUID> getAllPlayers() {
return players;
}
public ArrayList<UUID> getPlayers() {
ArrayList<UUID> playersInGame = new ArrayList<>(players);
playersInGame.removeIf(uuid -> getEliminated().contains(uuid));
return playersInGame;
}
public ArrayList<UUID> getEliminated() {
return eliminated;
}
public ArrayList<UUID> getEliminatedThisRound() {
return eliminatedThisRound;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void genName() {
UUID uuid = UUID.randomUUID();
if (!GameManager.gameLobbies.containsKey(uuid.toString())) {
name = uuid.toString();
} else {
genName();
}
}
public void setInstance(Instance instance, Pos pos) {
this.instance = instance;
players.forEach(player -> {
Objects.requireNonNull(MinecraftServer.getConnectionManager().getOnlinePlayerByUuid(player)).setInstance(instance)
.thenRun(() -> Objects.requireNonNull(MinecraftServer.getConnectionManager().getOnlinePlayerByUuid(player)).teleport(pos));
});
}
public Instance getInstance() {
return instance;
}
public void teleport(Pos pos) {
players.forEach(player -> {
Objects.requireNonNull(MinecraftServer.getConnectionManager().getOnlinePlayerByUuid(player)).teleport(pos);
});
}
public void sendMessage(ComponentLike component) {
players.forEach(player -> MinecraftServer.getConnectionManager().getOnlinePlayerByUuid(player).sendMessage(component));
}
}

View file

@ -0,0 +1,42 @@
package dev.cfox.gamejam.game.classes;
import dev.cfox.gamejam.game.managers.QueueManager;
import dev.cfox.gamejam.utils.Misc;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.GameMode;
import java.util.ArrayList;
import java.util.Objects;
import java.util.UUID;
public class GameQueue {
private final ArrayList<UUID> players = new ArrayList<>();
public void addPlayer(UUID uuid) {
if (QueueManager.getPlayerQueue(Misc.getPlayer(uuid)) == null) {
players.add(uuid);
Misc.getPlayer(uuid).setGameMode(GameMode.SPECTATOR);
Misc.getPlayer(uuid).sendMessage(Component.text("You've joined a queue!", NamedTextColor.GREEN));
} else {
Misc.getPlayer(uuid).sendMessage(Component.text("You're already in a queue!", NamedTextColor.RED));
}
}
public void removePlayer(UUID uuid) {
if (players.contains(uuid)) {
players.remove(uuid);
Misc.getPlayer(uuid).setGameMode(GameMode.SURVIVAL);
Misc.getPlayer(uuid).sendMessage(Component.text("You have left the queue", NamedTextColor.RED));
}
}
public ArrayList<UUID> getPlayers() {
return players;
}
public void sendMessage(Component component) {
players.forEach(uuid -> Misc.getPlayer(uuid).sendMessage(component));
}
}

View file

@ -0,0 +1,75 @@
package dev.cfox.gamejam.game.managers;
import dev.cfox.gamejam.game.classes.GameLobby;
import dev.cfox.gamejam.game.classes.GameQueue;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.title.Title;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance;
import java.util.*;
public class GameManager {
public static Map<String, GameLobby> gameLobbies = new HashMap<>();
public static boolean isPlayerInGame(Player player) {
for (GameLobby lobby : gameLobbies.values()) {
if (lobby.getAllPlayers().contains(player.getUuid())) {
return true;
}
}
return false;
}
public static void startGame(GameQueue queue) {
queue.sendMessage(Component.text("The game is starting!", NamedTextColor.GREEN, TextDecoration.BOLD));
// String game = LobbyConverter.toGame(queue);
QueueManager.removeQueue(queue);
}
public static GameLobby getPlayerGame(Player player) {
if (!gameLobbies.isEmpty()) {
for (GameLobby gameLobby : gameLobbies.values()) {
if (gameLobby.getAllPlayers().contains(player.getUuid())) {
return gameLobby;
}
}
}
return null;
}
public static GameLobby getGame(String lobby) {
return gameLobbies.get(lobby);
}
public static int getPlayersInGame() {
int totalPlayers = 0;
for (GameLobby gameLobby : gameLobbies.values()) {
totalPlayers += gameLobby.getAllPlayers().size();
}
return totalPlayers;
}
public static void sendEndTitles(GameLobby game) {
Instance instance = game.getInstance();
List<String> winners = new ArrayList<>();
List<UUID> eliminatedThisRound = game.getEliminatedThisRound();
for (Player player : instance.getPlayers()) {
if (eliminatedThisRound.contains(player.getUuid())) {
player.showTitle(Title.title(Component.text("Eliminated!", NamedTextColor.RED, TextDecoration.BOLD), Component.text("")));
} else {
// Player is a winner if they were not eliminated this round
if (!game.getEliminated().contains(player.getUuid())) {
player.showTitle(Title.title(Component.text("Qualified!", NamedTextColor.GREEN, TextDecoration.BOLD), Component.text("")));
winners.add(player.getUsername());
}
}
}
// Announce winners
instance.sendMessage(Component.text("Winner(s): " + winners, NamedTextColor.YELLOW, TextDecoration.BOLD));
}
}

View file

@ -1,4 +1,104 @@
package dev.cfox.gamejam.game.managers;
import dev.cfox.gamejam.game.classes.GameQueue;
import dev.cfox.gamejam.utils.Misc;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.title.Title;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.timer.Task;
import net.minestom.server.timer.TaskSchedule;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class QueueManager {
public static List<GameQueue> queues = new ArrayList<>();
private static final HashMap<GameQueue, Task> countdownTasks = new HashMap<>();
public static void joinPlayer(Player player) {
boolean queueFound = false;
if (!queues.isEmpty()) {
for (GameQueue queue : queues) {
if (queue.getPlayers().size() < 10) {
queue.addPlayer(player.getUuid());
queueFound = true;
if (queue.getPlayers().size() >= 6) {
startCountdown(queue);
}
break;
}
}
}
if (!queueFound) {
createQueue(player);
player.sendMessage(Component.text("No queues were found! A new queue has been created just for you.", NamedTextColor.GREEN));
}
}
public static void removePlayer(Player player) {
GameQueue queue = getPlayerQueue(player);
if (queue != null) {
queue.removePlayer(player.getUuid());
if (queue.getPlayers().size() < 2) {
stopCountdown(queue);
}
}
}
public static void createQueue(Player player) {
GameQueue newQueue = new GameQueue();
newQueue.addPlayer(player.getUuid());
queues.add(newQueue);
}
public static void removeQueue(GameQueue queue) {
queues.remove(queue);
}
public static GameQueue getPlayerQueue(Player player) {
return queues.stream()
.filter(queue -> queue.getPlayers().contains(player.getUuid()))
.findFirst()
.orElse(null);
}
private static void startCountdown(GameQueue queue) {
// Check if a countdown task is already running for the queue
if (countdownTasks.containsKey(queue)) {
return;
}
final int[] countdown = {5}; // Countdown timer in seconds
// Schedule a task to send the title every second
Task task = MinecraftServer.getSchedulerManager().buildTask(() -> {
queue.getPlayers().forEach(player -> Misc.getPlayer(player).showTitle(Title.title(
Component.text("Starting in " + countdown[0], NamedTextColor.GREEN),
Component.text("Get ready", NamedTextColor.GRAY))));
if (countdown[0] == 0) {
// Time's up, cancel the task and start the game
GameManager.startGame(queue);
countdownTasks.get(queue).cancel();
countdownTasks.remove(queue);
}
countdown[0]--;
}).repeat(TaskSchedule.seconds(1)).schedule();
countdownTasks.put(queue, task);
}
private static void stopCountdown(GameQueue queue) {
if (countdownTasks.containsKey(queue)) {
Task countdownTask = countdownTasks.get(queue);
countdownTask.cancel();
countdownTasks.remove(queue);
}
}
}

View file

@ -1,8 +1,14 @@
package dev.cfox.gamejam.game;
package dev.cfox.gamejam.game.phases;
import dev.cfox.gamejam.utils.events.StartEvents;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Random;
public class Phase {
private static final Logger logger = LoggerFactory.getLogger(Phase.class);
public static void random() {
Phases[] phases = Phases.values();
int randomIndex = new Random().nextInt(phases.length);

View file

@ -1,4 +1,4 @@
package dev.cfox.gamejam.game;
package dev.cfox.gamejam.game.phases;
public enum Phases {
RED,

View file

@ -2,10 +2,17 @@ package dev.cfox.gamejam.utils;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.title.Title;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance;
import java.util.UUID;
public class Misc {
public static Player getPlayer(UUID uuid) {
return MinecraftServer.getConnectionManager().getOnlinePlayerByUuid(uuid);
}
public static void showTitle(Instance instance, Component title, Component subtitle) {
for (Player player : instance.getPlayers()) { // Get all players in the instance
player.showTitle(Title.title(title, subtitle)); // Send the title to each player

View file

@ -1,4 +1,68 @@
package dev.cfox.gamejam.utils;
package dev.cfox.gamejam.utils.classes;
public class NPC {
import net.minestom.server.entity.*;
import net.minestom.server.entity.metadata.PlayerMeta;
import net.minestom.server.network.packet.server.play.EntityMetaDataPacket;
import net.minestom.server.network.packet.server.play.PlayerInfoRemovePacket;
import net.minestom.server.network.packet.server.play.PlayerInfoUpdatePacket;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Map;
@SuppressWarnings("UnstableApiUsage")
public class NPC extends Entity {
private final String username;
private final String skinTexture;
private final String skinSignature;
public NPC(@NotNull String username, @Nullable String skinTexture, @Nullable String skinSignature) {
super(EntityType.PLAYER);
this.username = username;
this.skinTexture = skinTexture;
this.skinSignature = skinSignature;
setNoGravity(true);
}
@Override
public void updateNewViewer(@NotNull Player player) {
var properties = new ArrayList<PlayerInfoUpdatePacket.Property>();
if (skinTexture != null && skinSignature != null) {
properties.add(new PlayerInfoUpdatePacket.Property("textures", skinTexture, skinSignature));
}
var entry = new PlayerInfoUpdatePacket.Entry(getUuid(), username, properties, false,
0, GameMode.SURVIVAL, null, null);
player.sendPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.ADD_PLAYER, entry));
// Spawn the player entity
super.updateNewViewer(player);
setSkin();
player.sendPackets(new EntityMetaDataPacket(getEntityId(), Map.of(17, Metadata.Byte((byte) 127))));
}
@Override
public void updateOldViewer(@NotNull Player player) {
super.updateOldViewer(player);
player.sendPacket(new PlayerInfoRemovePacket(getUuid()));
}
public void setSkin() {
PlayerMeta meta = (PlayerMeta) this.entityMeta;
// Nice and pretty second layer
meta.setNotifyAboutChanges(false);
meta.setCapeEnabled(true);
meta.setHatEnabled(true);
meta.setJacketEnabled(true);
meta.setLeftLegEnabled(true);
meta.setRightLegEnabled(true);
meta.setLeftSleeveEnabled(true);
meta.setRightSleeveEnabled(true);
meta.setNotifyAboutChanges(true);
}
}

View file

@ -0,0 +1,22 @@
package dev.cfox.gamejam.utils.classes;
import net.kyori.adventure.text.Component;
import net.minestom.server.entity.Player;
import java.util.Random;
public class Randomized {
public static Component elimination(Player player) {
Random rand = new Random();
int message = rand.nextInt(4);
String elIcon = "§7[§r☠§7] §b§l";
return switch (message) {
case 0 -> Component.text(elIcon + player.getUsername() + " §cshould try Roblox.");
case 1 -> Component.text(elIcon + player.getUsername() + " §cdidn't try good enough.");
case 2 -> Component.text(elIcon + player.getUsername() + " §cded.");
case 3 -> Component.text(elIcon + player.getUsername() + " §cthought they were God.");
default -> Component.text(elIcon + player.getUsername() + " §cgot eliminated.");
};
}
}

View file

@ -1,6 +1,5 @@
package dev.cfox.gamejam.utils;
package dev.cfox.gamejam.utils.config;
import dev.cfox.gamejam.utils.config.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View file

@ -1,4 +1,4 @@
package dev.celestialfox.gamejam.utils.config;
package dev.cfox.gamejam.utils.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -21,16 +21,17 @@ public class Configuration {
}
public static void createDefaultConfig() {
logger.info("Config file does not exist. Creating default config file...");
try (FileOutputStream outputStream = new FileOutputStream(CONFIG_FILE)) {
properties.setProperty("server.ip", "0.0.0.0");
properties.setProperty("server.port", "25565");
properties.store(outputStream, "Server Configuration");
logger.info("Default config file created successfully.");
loadConfig();
} catch (IOException e) {
logger.error("Error while creating default config file: " + e.getMessage());
}
loadConfig();
}
static String getServerIp() {

View file

@ -1,4 +1,4 @@
package dev.celestialfox.gamejam.utils.config;
package dev.cfox.gamejam.utils.config;
public class Settings {
public static String getIP() {

View file

@ -1,4 +1,4 @@
package dev.celestialfox.gamejam.utils.conversion;
package dev.cfox.gamejam.utils.conversion;
public class Polar {
public static void convertFolder(String folder) {

View file

@ -1,20 +1,25 @@
package dev.celestialfox.gamejam.utils.events;
package dev.cfox.gamejam.utils.events;
import dev.cfox.gamejam.utils.Misc;
import dev.cfox.gamejam.utils.classes.NPC;
import dev.cfox.gamejam.utils.classes.Randomized;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player;
import net.minestom.server.event.GlobalEventHandler;
import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
import net.minestom.server.event.player.PlayerChatEvent;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.instance.LightingChunk;
import net.minestom.server.event.player.PlayerSpawnEvent;
import net.minestom.server.instance.*;
import net.minestom.server.instance.block.Block;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Duration;
public class StartEvents {
static GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler();
private static final Logger logger = LoggerFactory.getLogger(StartEvents.class);
@ -36,20 +41,42 @@ public class StartEvents {
}
public static void handleSpawn() {
logger.debug("Registering Spawn Listener");
InstanceContainer instanceContainer = createSpawnInstance();
InstanceContainer instanceContainer = createLobbyInstance();
globalEventHandler.addListener(AsyncPlayerConfigurationEvent.class, event -> {
final Player player = event.getPlayer();
event.setSpawningInstance(instanceContainer);
player.setRespawnPoint(new Pos(0, 42, 0));
});
globalEventHandler.addListener(PlayerSpawnEvent.class, event -> {
Player player = event.getPlayer();
if (event.isFirstSpawn()) {
var mm = MiniMessage.miniMessage();
Component minestom = mm.deserialize("<gradient:#5e4fa2:#f79459:red>Minestom NPC</gradient>");
player.sendMessage(Component.text(
"§e§lClick on §ror §e§lrun into §rthe ", NamedTextColor.GRAY).append(minestom).append(Component.text(" to §a§ljoin the queue!")));
Misc.showTitle(player.getInstance(), Component.text("", NamedTextColor.RED), Component.text("Red", NamedTextColor.RED));
}
public static InstanceContainer createSpawnInstance() {
logger.debug("Creating Spawn Instance");
});
}
public static InstanceContainer createLobbyInstance() {
logger.debug("Creating Lobby Instance");
InstanceManager instanceManager = MinecraftServer.getInstanceManager();
InstanceContainer instanceContainer = instanceManager.createInstanceContainer();
// try {
// instanceContainer.setChunkLoader(new PolarLoader(Path.of("worlds/lobby.polar")));
// } catch (IOException e) {
// logger.error(e.getMessage());
// }
instanceContainer.setGenerator(unit -> unit.modifier().fillHeight(0, 40, Block.GRASS_BLOCK));
instanceContainer.setChunkSupplier(LightingChunk::new);
NPC joinNPC = new NPC("Join the Queue",
"ewogICJ0aW1lc3RhbXAiIDogMTY3MjE3MTU1MjU1OCwKICAicHJvZmlsZUlkIiA6ICJiNTAwOGEyMGJkY2U0YjJlOTU5NWZlNzY2MDlmYjUzNiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNT1JJU3hTVE9QQkFOIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2RmZDIwOWU5ZTk2MGY4MDQ5ZDdlYWY0NTJmYzg1YmYwYmVjZjliMTUwYjQ2MzIwMTY2Mjg1YzdhYjEzMjMxN2UiCiAgICB9CiAgfQp9",
"yWIH6gVDRhgd/HwVYpRT87NBHf+q9EgYs/CYqIwnz5xXR22k29c7MTnaYFvWukbwF1FhWNilAyYzagSn/7ScvOpYn0RtyTWk656cwjzFSbTsSFzRwUl5f4mu1EeunYh8v5cZH27KTfAI7a9Q7ylXz7NoAbvaw056thXa7jHhLhFdPECnziRTnv9jDRwpoN/4jblmdOz5NCLtynubf8hwIwm9od18tXy4+gsV3aXS5+1MirpWDizqdozb9mtwzML9NYwVNpO2bRB9KYJ91VUWqxjfTy/q0xFQ1paolq4pp3tgvLXw0y+rdwCsCgh39JA4MKvIIJShww5xbqo4oFBRDj+/BI3+Y154Ess1004vE+iTRdt+az0v4y+evnOQLgryEr/36QzZOndpSFqYfKPl1MeUeZe1u4VDQJcgyJImg2TZJbG2WOmmTySWSEPrHcYC6c3Y9rVnQ6Zi4NxTe4e6/ZuDQVm14fuSUPd4Ll7/aIDyumHupBMMbBEa9qCmuZJPT5iWVlIGfzA2Dg/kea4Jw9WudUmiCYngB56HZEivDPniIxeGSTRFHMR2FfTKnLkxb2LDOvD+CgDWyr8cGy4xnB2hwdY2n28cCAYI5axj0qzCpHMl8Y90e2rKfX7NsUvyivbAVRwAsd/bWkkJoZ4/QStFEjV//81iNbuUz/4lFQA=");
joinNPC.setInstance(instanceContainer, new Pos(0, 40, 0));
return instanceContainer;
}
}

View file

@ -0,0 +1,11 @@
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
</root>
</configuration>