├── .gitignore ├── README.md ├── README_EN.md ├── images ├── base.png ├── building.png ├── coi_logo.png ├── coi_logo2.png ├── door.png ├── farmer.png ├── fighter.png ├── health.png ├── miner.png ├── openDoor.png ├── turret.png └── wall.png ├── libs ├── Citizens-2.0.31-b3096.jar └── Hermes.jar ├── pdm ├── realm.PDM └── realm.pdb ├── pom.xml └── src └── main ├── java └── com │ └── mcylm │ └── coi │ └── realm │ ├── Entry.java │ ├── clipboard │ └── PlayerClipboard.java │ ├── cmd │ ├── AllCommand.java │ ├── COIStructureCommand.java │ ├── DebugCommand.java │ ├── SpawnPointCommand.java │ └── VeinCommand.java │ ├── conf │ └── Configuration.java │ ├── enums │ ├── AttackGoalType.java │ ├── COIBuildingType.java │ ├── COIGUIType.java │ ├── COIGameStatus.java │ ├── COIHeadType.java │ ├── COIMultipleGameMode.java │ ├── COIPermissionType.java │ ├── COIScoreType.java │ ├── COIServerMode.java │ ├── COITeamType.java │ ├── COIUnlockType.java │ └── types │ │ ├── COIBuildingTypes.java │ │ └── COIUnlockTypes.java │ ├── events │ ├── BuildingDamagedEvent.java │ ├── BuildingDestroyedEvent.java │ ├── BuildingTouchEvent.java │ └── GameStatusEvent.java │ ├── game │ └── COIGame.java │ ├── gui │ ├── BuildEditGUI.java │ ├── BuilderGUI.java │ ├── ChooseTeamGUI.java │ ├── ForgeGUI.java │ ├── GuiBuilder │ │ ├── COIPageGuiBuilder.java │ │ └── COIPaginatedGui.java │ ├── SkinGUI.java │ └── SkinTypeGUI.java │ ├── item │ ├── COICustomItem.java │ └── impl │ │ ├── COICustomItems.java │ │ └── tools │ │ ├── COIRocket.java │ │ └── COITownPortal.java │ ├── listener │ ├── GameListener.java │ ├── MineralsBreakListener.java │ ├── PlayerInteractListener.java │ └── SnowballCoolDownListener.java │ ├── managers │ ├── COIBuildingManager.java │ └── CustomItemManager.java │ ├── model │ ├── COIBlock.java │ ├── COINpc.java │ ├── COIPaster.java │ ├── COIPlayerScore.java │ ├── COIPosition.java │ ├── COIScore.java │ ├── COIScoreDetail.java │ ├── COISkin.java │ ├── COIStructure.java │ ├── COITurretLocation.java │ └── ClipboardLocation.java │ ├── player │ ├── COIPlayer.java │ └── settings │ │ ├── GoalSetting.java │ │ └── PlayerSettings.java │ ├── runnable │ ├── AirRaidTask.java │ ├── AttackGoalTask.java │ ├── BasicGameTask.java │ ├── NpcAITask.java │ ├── RepairTask.java │ ├── TaskRunnable.java │ ├── TurretTask.java │ ├── VeinGenerateTask.java │ └── api │ │ └── GameTaskApi.java │ ├── tools │ ├── attack │ │ ├── AttackGoal.java │ │ ├── Commandable.java │ │ ├── DamageableAI.java │ │ ├── impl │ │ │ ├── FollowGoal.java │ │ │ ├── GatherGoal.java │ │ │ ├── GuardGoal.java │ │ │ ├── PatrolGoal.java │ │ │ ├── SimpleGoal.java │ │ │ └── TeamFollowGoal.java │ │ ├── target │ │ │ ├── Target.java │ │ │ ├── TargetType.java │ │ │ └── impl │ │ │ │ ├── BuildingTarget.java │ │ │ │ └── EntityTarget.java │ │ └── team │ │ │ └── AttackTeam.java │ ├── building │ │ ├── Builder.java │ │ ├── COIBuilding.java │ │ ├── ConnectableBuild.java │ │ ├── FloatableBuild.java │ │ ├── LineBuild.java │ │ ├── config │ │ │ └── BuildingConfig.java │ │ └── impl │ │ │ ├── COIAirRaid.java │ │ │ ├── COIBase.java │ │ │ ├── COIBridge.java │ │ │ ├── COIBuilder.java │ │ │ ├── COICamp.java │ │ │ ├── COIDoor.java │ │ │ ├── COIForge.java │ │ │ ├── COIMill.java │ │ │ ├── COIRepair.java │ │ │ ├── COIStope.java │ │ │ ├── COITurret.java │ │ │ ├── COIWall.java │ │ │ ├── COIWallOld.java │ │ │ └── monster │ │ │ └── COIMonsterBase.java │ ├── data │ │ ├── MapData.java │ │ ├── SkinData.java │ │ └── metadata │ │ │ ├── AttackTeamData.java │ │ │ ├── BuildData.java │ │ │ ├── EntityData.java │ │ │ └── MonsterData.java │ ├── goals │ │ ├── citizens │ │ │ ├── NPCFeedFoodBehavior.java │ │ │ ├── NPCLookForTargetGoal.java │ │ │ ├── NPCMoveAroundBehavior.java │ │ │ ├── NPCMoveToTargetPointGoal.java │ │ │ └── NPCSimpleMeleeAttackGoal.java │ │ └── paper │ │ │ ├── MonsterAttackBuildingGoal.java │ │ │ └── MonsterLookForBuildingTargetGoal.java │ ├── handler │ │ ├── BlockPlaceCondition.java │ │ ├── BlockPlaceHandler.java │ │ └── SpawnHandler.java │ ├── map │ │ ├── COIMobSpawnPoint.java │ │ └── COIVein.java │ ├── monster │ │ ├── Monsters.java │ │ └── custom │ │ │ ├── CustomMonster.java │ │ │ └── impl │ │ │ ├── GiantMonster.java │ │ │ └── VanillaMonster.java │ ├── npc │ │ ├── AI.java │ │ ├── COICartCreator.java │ │ ├── COIFarmerCreator.java │ │ ├── COIMinerCreator.java │ │ ├── COISmithCreator.java │ │ ├── COISoldierCreator.java │ │ ├── impl │ │ │ ├── COICart.java │ │ │ ├── COIEntity.java │ │ │ ├── COIFarmer.java │ │ │ ├── COIMiner.java │ │ │ ├── COISmith.java │ │ │ ├── COISoldier.java │ │ │ └── monster │ │ │ │ ├── COIMonster.java │ │ │ │ ├── COIPillager.java │ │ │ │ └── COIPillagerCaptain.java │ │ └── monster │ │ │ ├── COIMonsterCreator.java │ │ │ └── COIPillagerCreator.java │ ├── selection │ │ ├── AreaSelector.java │ │ ├── FloatableSelector.java │ │ ├── LineSelector.java │ │ └── Selector.java │ ├── team │ │ ├── Team.java │ │ └── impl │ │ │ ├── COIScoreboard.java │ │ │ └── COITeam.java │ └── trait │ │ └── DisguiseTrait.java │ └── utils │ ├── ChestUtils.java │ ├── DamageUtils.java │ ├── FileUtils.java │ ├── FormationUtils.java │ ├── GUIUtils.java │ ├── InventoryUtils.java │ ├── ItemUtils.java │ ├── JsonUtils.java │ ├── LocationUtils.java │ ├── LoggerUtils.java │ ├── MapUtils.java │ ├── ScheduleUtils.java │ ├── ServerUtils.java │ ├── SkullUtils.java │ ├── TeamUtils.java │ ├── TimeUtils.java │ ├── WearUtils.java │ ├── particle │ └── ParticleRect.java │ ├── region │ └── Region.java │ └── rotation │ ├── Rotation.java │ └── Vector2Int.java └── resources ├── assembly.xml ├── backup ├── 2teammap.json └── 6teammap.json ├── config.yml ├── map.json └── plugin.yml /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.idea/ 3 | .idea/workspace.xml 4 | *.structure 5 | -------------------------------------------------------------------------------- /images/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clayun/coi-realm/b21e0dc8512f7651244c2d293b2a68b1cdb287f9/images/base.png -------------------------------------------------------------------------------- /images/building.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clayun/coi-realm/b21e0dc8512f7651244c2d293b2a68b1cdb287f9/images/building.png -------------------------------------------------------------------------------- /images/coi_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clayun/coi-realm/b21e0dc8512f7651244c2d293b2a68b1cdb287f9/images/coi_logo.png -------------------------------------------------------------------------------- /images/coi_logo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clayun/coi-realm/b21e0dc8512f7651244c2d293b2a68b1cdb287f9/images/coi_logo2.png -------------------------------------------------------------------------------- /images/door.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clayun/coi-realm/b21e0dc8512f7651244c2d293b2a68b1cdb287f9/images/door.png -------------------------------------------------------------------------------- /images/farmer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clayun/coi-realm/b21e0dc8512f7651244c2d293b2a68b1cdb287f9/images/farmer.png -------------------------------------------------------------------------------- /images/fighter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clayun/coi-realm/b21e0dc8512f7651244c2d293b2a68b1cdb287f9/images/fighter.png -------------------------------------------------------------------------------- /images/health.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clayun/coi-realm/b21e0dc8512f7651244c2d293b2a68b1cdb287f9/images/health.png -------------------------------------------------------------------------------- /images/miner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clayun/coi-realm/b21e0dc8512f7651244c2d293b2a68b1cdb287f9/images/miner.png -------------------------------------------------------------------------------- /images/openDoor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clayun/coi-realm/b21e0dc8512f7651244c2d293b2a68b1cdb287f9/images/openDoor.png -------------------------------------------------------------------------------- /images/turret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clayun/coi-realm/b21e0dc8512f7651244c2d293b2a68b1cdb287f9/images/turret.png -------------------------------------------------------------------------------- /images/wall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clayun/coi-realm/b21e0dc8512f7651244c2d293b2a68b1cdb287f9/images/wall.png -------------------------------------------------------------------------------- /libs/Citizens-2.0.31-b3096.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clayun/coi-realm/b21e0dc8512f7651244c2d293b2a68b1cdb287f9/libs/Citizens-2.0.31-b3096.jar -------------------------------------------------------------------------------- /libs/Hermes.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Clayun/coi-realm/b21e0dc8512f7651244c2d293b2a68b1cdb287f9/libs/Hermes.jar -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/cmd/AllCommand.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.cmd; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.enums.COIGameStatus; 5 | import com.mcylm.coi.realm.runnable.VeinGenerateTask; 6 | import com.mcylm.coi.realm.tools.map.COIVein; 7 | import com.mcylm.coi.realm.tools.team.impl.COITeam; 8 | import com.mcylm.coi.realm.utils.LoggerUtils; 9 | import com.mcylm.coi.realm.utils.TeamUtils; 10 | import org.bukkit.Bukkit; 11 | import org.bukkit.Location; 12 | import org.bukkit.command.Command; 13 | import org.bukkit.command.CommandExecutor; 14 | import org.bukkit.command.CommandSender; 15 | import org.bukkit.entity.Player; 16 | import org.bukkit.scheduler.BukkitRunnable; 17 | import org.jetbrains.annotations.NotNull; 18 | 19 | import java.util.ArrayList; 20 | import java.util.Comparator; 21 | import java.util.List; 22 | 23 | public class AllCommand implements CommandExecutor { 24 | 25 | 26 | @Override 27 | public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] args) { 28 | if (commandSender instanceof Player player) { 29 | if (args.length >= 1) { 30 | if(Entry.getGame().getStatus().equals(COIGameStatus.GAMING)){ 31 | 32 | // 消息 33 | String message = String.join(" ", args); 34 | 35 | COITeam teamByPlayer = TeamUtils.getTeamByPlayer(player); 36 | // 游戏中 37 | for(Player p : Bukkit.getOnlinePlayers()){ 38 | LoggerUtils.sendAllChatMessage(teamByPlayer.getType().getColor()+"<"+player.getName()+">" + " &f"+message, p); 39 | } 40 | 41 | // 记录聊天日志 42 | LoggerUtils.log(teamByPlayer.getType().getColor()+"<"+player.getName()+">" + " &f"+message); 43 | 44 | return true; 45 | }else{ 46 | LoggerUtils.sendAllChatMessage("&7游戏尚未开始,无需全局喊话",player); 47 | 48 | return true; 49 | } 50 | } 51 | } 52 | return false; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/cmd/DebugCommand.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.cmd; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.enums.COIBuildingType; 5 | import com.mcylm.coi.realm.gui.ChooseTeamGUI; 6 | import com.mcylm.coi.realm.tools.building.COIBuilding; 7 | import com.mcylm.coi.realm.tools.npc.monster.COIPillagerCreator; 8 | import com.mcylm.coi.realm.utils.LoggerUtils; 9 | import com.mcylm.coi.realm.utils.TeamUtils; 10 | import org.bukkit.Bukkit; 11 | import org.bukkit.Location; 12 | import org.bukkit.attribute.Attribute; 13 | import org.bukkit.command.Command; 14 | import org.bukkit.command.CommandExecutor; 15 | import org.bukkit.command.CommandSender; 16 | import org.bukkit.entity.LivingEntity; 17 | import org.bukkit.entity.Player; 18 | import org.jetbrains.annotations.NotNull; 19 | 20 | import java.util.List; 21 | 22 | public class DebugCommand implements CommandExecutor { 23 | @Override 24 | public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] args) { 25 | if(!(commandSender instanceof Player player)){ 26 | // 这个指令只能让玩家使用 27 | // This command only player can use 28 | LoggerUtils.sendMessage("这个指令只能让玩家使用。",commandSender); 29 | return false; 30 | } 31 | 32 | if(args.length == 0){ 33 | LoggerUtils.sendMessage("参数不对。",commandSender); 34 | return false; 35 | } 36 | 37 | if(!commandSender.isOp()){ 38 | LoggerUtils.sendMessage("没有权限。",commandSender); 39 | return false; 40 | } 41 | 42 | if (args[0].equalsIgnoreCase("team")) { 43 | new ChooseTeamGUI(player).open(); 44 | } 45 | if (args[0].equalsIgnoreCase("monster")) { 46 | try { 47 | COIBuilding building = Entry.getInstance().getBuildingManager().getBuildingTemplateByType(COIBuildingType.MONSTER_BASE); 48 | building.setNpcCreators(List.of(COIPillagerCreator.initCOIPillagerCreator(null))); 49 | building.setTeam(TeamUtils.getMonsterTeam()); 50 | 51 | Location clone = player.getLocation().clone(); 52 | clone.setY(clone.getY() - 1); 53 | building.build(clone,TeamUtils.getMonsterTeam(),false ); 54 | } catch (Exception e) { 55 | throw new RuntimeException(e); 56 | } 57 | 58 | } 59 | 60 | if(args[0].equalsIgnoreCase("speed")){ 61 | 62 | if(args.length < 3){ 63 | LoggerUtils.sendMessage("参数错误。",commandSender); 64 | return false; 65 | } 66 | String targetPlayerName = args[1]; 67 | 68 | Player target = Bukkit.getPlayer(targetPlayerName); 69 | 70 | if(target != null){ 71 | // 更改移动速度 72 | LivingEntity entity = target; 73 | entity.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(Double.valueOf(args[2])); 74 | 75 | } 76 | } 77 | 78 | if(args[0].equalsIgnoreCase("fly")){ 79 | 80 | if(args.length < 3){ 81 | LoggerUtils.sendMessage("参数错误。",commandSender); 82 | return false; 83 | } 84 | String targetPlayerName = args[1]; 85 | 86 | Player target = Bukkit.getPlayer(targetPlayerName); 87 | 88 | if(target != null){ 89 | // 更改飞行速度 90 | target.setFlySpeed(Float.valueOf(args[2])); 91 | } 92 | } 93 | 94 | if(args[0].equalsIgnoreCase("test")){ 95 | 96 | } 97 | 98 | return true; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/cmd/SpawnPointCommand.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.cmd; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.tools.map.COIMobSpawnPoint; 5 | import com.mcylm.coi.realm.utils.LoggerUtils; 6 | import org.bukkit.Location; 7 | import org.bukkit.command.Command; 8 | import org.bukkit.command.CommandExecutor; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.entity.Player; 11 | import org.bukkit.scheduler.BukkitRunnable; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.util.ArrayList; 15 | import java.util.Comparator; 16 | import java.util.List; 17 | 18 | public class SpawnPointCommand implements CommandExecutor { 19 | @Override 20 | public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] args) { 21 | if (commandSender instanceof Player player) { 22 | if (player.hasPermission("coi.realm.spawnpoint")) { 23 | if (args.length >= 1 && args[0].equals("remove")) { 24 | List points = new ArrayList<>(Entry.getMapData().getMobSpawnPoints()); 25 | points.sort(Comparator.comparingDouble(vein -> vein.getLocation().getWorld() == player.getWorld() ? vein.getLocation().distance(player.getLocation()) : Integer.MAX_VALUE)); 26 | COIMobSpawnPoint point = points.get(0); 27 | Entry.getMapData().getVeins().remove(point); 28 | LoggerUtils.sendMessage("&c已删除离你最近的生成点: " + point.getLocation() ,player); 29 | new BukkitRunnable() { 30 | @Override 31 | public void run() { 32 | Entry.getInstance().saveMapData(); 33 | } 34 | }.runTaskAsynchronously(Entry.getInstance()); 35 | } else if (args.length >= 1 && args[0].equals("create")) { 36 | 37 | int maxRadius = Integer.parseInt(args[1]); 38 | // String targetTeam = args[1]; 39 | Location location = player.getLocation(); 40 | COIMobSpawnPoint point = new COIMobSpawnPoint(location.getBlockX(), location.getBlockY(), location.getBlockZ(), location.getWorld().getName(), maxRadius); 41 | Entry.getMapData().getMobSpawnPoints().add(point); 42 | LoggerUtils.sendMessage("&a成功添加", player); 43 | 44 | new BukkitRunnable() { 45 | @Override 46 | public void run() { 47 | Entry.getInstance().saveMapData(); 48 | } 49 | }.runTaskAsynchronously(Entry.getInstance()); 50 | } 51 | } 52 | } 53 | return false; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/cmd/VeinCommand.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.cmd; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.runnable.VeinGenerateTask; 5 | import com.mcylm.coi.realm.tools.map.COIVein; 6 | import com.mcylm.coi.realm.utils.LoggerUtils; 7 | import org.bukkit.Location; 8 | import org.bukkit.command.Command; 9 | import org.bukkit.command.CommandExecutor; 10 | import org.bukkit.command.CommandSender; 11 | import org.bukkit.entity.Player; 12 | import org.bukkit.scheduler.BukkitRunnable; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Comparator; 17 | import java.util.List; 18 | 19 | public class VeinCommand implements CommandExecutor { 20 | 21 | 22 | @Override 23 | public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] args) { 24 | if (commandSender instanceof Player player) { 25 | if (player.hasPermission("coi.realm.vein")) { 26 | if (args.length >= 1 && args[0].equals("remove")) { 27 | List veins = new ArrayList<>(Entry.getMapData().getVeins()); 28 | veins.sort(Comparator.comparingDouble(vein -> vein.getLocation().getWorld() == player.getWorld() ? vein.getLocation().distance(player.getLocation()) : Integer.MAX_VALUE)); 29 | COIVein vein = veins.get(0); 30 | Entry.getMapData().getVeins().remove(vein); 31 | LoggerUtils.sendMessage("&c已删除离你最近的矿脉: " + vein.getLocation() ,player); 32 | new BukkitRunnable() { 33 | @Override 34 | public void run() { 35 | Entry.getInstance().saveMapData(); 36 | } 37 | }.runTaskAsynchronously(Entry.getInstance()); 38 | } else if (args.length >= 1 && args[0].equals("create")) { 39 | // create 40 | 41 | String structureName = args[1]; 42 | double chance = (args.length >= 3) ? Double.parseDouble(args[2]) : 0.5; 43 | int resetTime = (args.length >= 4) ? Integer.parseInt(args[3]) : 60; 44 | Location location = player.getLocation(); 45 | COIVein vein = new COIVein(structureName, location.getBlockX(), location.getBlockY(), location.getBlockZ(), location.getYaw(), location.getWorld().getName(), chance, resetTime); 46 | Entry.getMapData().getVeins().add(vein); 47 | LoggerUtils.sendMessage("&a成功添加", player); 48 | 49 | new BukkitRunnable() { 50 | @Override 51 | public void run() { 52 | Entry.getInstance().saveMapData(); 53 | } 54 | }.runTaskAsynchronously(Entry.getInstance()); 55 | } else if (args.length >= 1 && args[0].equalsIgnoreCase("test")) { 56 | VeinGenerateTask.runTask(); 57 | 58 | } 59 | } 60 | } 61 | return false; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/conf/Configuration.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.conf; 2 | 3 | import org.bukkit.configuration.InvalidConfigurationException; 4 | import org.bukkit.configuration.file.FileConfiguration; 5 | import org.bukkit.configuration.file.YamlConfiguration; 6 | import org.bukkit.plugin.java.JavaPlugin; 7 | 8 | import java.io.*; 9 | 10 | public class Configuration { 11 | 12 | /** 13 | * Create a config from the given inputstream and file. Creates file if it 14 | * does not exist 15 | * 16 | * @param stream 17 | * InputStream to write to file if it does not exist 18 | * @param file 19 | * File object for configuration 20 | * @return 21 | */ 22 | public static FileConfiguration createConfig(InputStream stream, File file) { 23 | 24 | if (!file.exists()) { 25 | 26 | file.getParentFile().mkdirs(); 27 | copy(stream, file); 28 | 29 | } 30 | return YamlConfiguration.loadConfiguration(file); 31 | 32 | } 33 | 34 | /** 35 | * Create a config based on a resource file contained in the plugin 36 | * 37 | * @param plugin 38 | * Main class of plugin possessing the resource file 39 | * @param resource 40 | * String filename of resource inside the plugin 41 | * @param file 42 | * File object for configuration 43 | * @return 44 | */ 45 | public static FileConfiguration createConfig(JavaPlugin plugin, String resource, 46 | File file) { 47 | 48 | if (!file.exists()) { 49 | file.getParentFile().mkdirs(); 50 | copy(plugin.getResource(resource), file); 51 | } 52 | return YamlConfiguration.loadConfiguration(file); 53 | 54 | } 55 | 56 | /** 57 | * Create a config based on a resource file contained in the plugin 58 | * 59 | * @param plugin 60 | * Main class of plugin possessing the resource file 61 | * @param resource 62 | * String filename of resource inside the plugin 63 | * @param filename 64 | * Name of file to create 65 | * @return 66 | */ 67 | public static FileConfiguration createConfig(JavaPlugin plugin, String resource, 68 | String filename) { 69 | 70 | File file = new File(filename); 71 | 72 | if (!file.exists()) { 73 | file.getParentFile().mkdirs(); 74 | copy(plugin.getResource(resource), file); 75 | } 76 | return YamlConfiguration.loadConfiguration(file); 77 | 78 | } 79 | 80 | /** 81 | * Create FileConfiguration from the given file 82 | * 83 | * @param file 84 | * File to load from config 85 | * @return 86 | * @throws FileNotFoundException 87 | * If file does not exist 88 | * @throws InvalidConfigurationException 89 | * If there is an invalid configuration 90 | */ 91 | public static FileConfiguration createConfig(File file){ 92 | if (!file.exists()) { 93 | try { 94 | file.createNewFile(); 95 | } catch (IOException e) { 96 | e.printStackTrace(); 97 | } 98 | } 99 | return YamlConfiguration.loadConfiguration(file); 100 | } 101 | 102 | /** 103 | * Create a folder in the given location 104 | * @param location Parent location 105 | * @param name Folder/Directory name 106 | * @return 107 | */ 108 | public static File mkdirs(File location, String name) { 109 | File dir = new File(location, name); 110 | if (!dir.exists()) { 111 | dir.mkdirs(); 112 | } 113 | return dir; 114 | } 115 | 116 | private static void copy(InputStream in, File file) { 117 | 118 | try { 119 | 120 | OutputStream out = new FileOutputStream(file); 121 | byte[] buf = new byte[1024]; 122 | int len; 123 | while ((len = in.read(buf)) > 0) { 124 | 125 | out.write(buf, 0, len); 126 | 127 | } 128 | out.close(); 129 | in.close(); 130 | 131 | } catch (Exception e) { 132 | 133 | e.printStackTrace(); 134 | 135 | } 136 | 137 | } 138 | 139 | } -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/enums/AttackGoalType.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import org.bukkit.Material; 6 | @AllArgsConstructor 7 | @Getter 8 | public enum AttackGoalType { 9 | GUARD("镇守", Material.SHIELD, "原地镇守"), 10 | PATROL("巡逻", Material.BOW, "四处转转"), 11 | ATTACK("主动进攻", Material.IRON_SWORD, "主动进攻"), 12 | FOLLOW("跟随", Material.NAME_TAG, "跟随命令者"), 13 | LOCK("锁定", Material.DIAMOND_SWORD, "锁定几个目标进行攻击"), 14 | GATHER("集合", Material.FEATHER,"将NPC呼唤至命令者"), 15 | TEAM_FOLLOW("列队跟随", Material.NAME_TAG, "跟随队伍") 16 | ; 17 | private String name; 18 | // GUI显示的材质 19 | private Material itemType; 20 | // 介绍 21 | private String introduce; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/enums/COIGUIType.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import net.kyori.adventure.text.Component; 6 | 7 | /** 8 | * GUI的类型 9 | */ 10 | @Getter 11 | @AllArgsConstructor 12 | public enum COIGUIType { 13 | 14 | CHOOSE_TEAM_GUI("选择队伍界面",Component.text("选择要加入的小队")), 15 | ; 16 | 17 | // GUI名称 18 | private String name; 19 | // GUI Component 20 | private Component component; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/enums/COIGameStatus.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.Getter; 6 | 7 | /** 8 | * 游戏状态 9 | */ 10 | @Getter 11 | @AllArgsConstructor 12 | public enum COIGameStatus { 13 | 14 | WAITING("WAITING","等待中","等待中可以选择或更换队伍"), 15 | GAMING("GAMING","游戏中","游戏进行中的状态"), 16 | STOPPING("STOPPING","结算中","游戏已结束,正在给玩家结算奖励"), 17 | ; 18 | 19 | // 状态CODE 20 | private String code; 21 | // 状态名称 22 | private String name; 23 | // 状态备注 24 | private String remark; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/enums/COIHeadType.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.enums; 2 | 3 | import com.mcylm.coi.realm.tools.building.COIBuilding; 4 | import com.mcylm.coi.realm.tools.team.impl.COITeam; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Getter; 7 | import org.bukkit.Material; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * 解锁类型 13 | */ 14 | @Getter 15 | @AllArgsConstructor 16 | public enum COIHeadType { 17 | 18 | // 上锁的箱子 19 | LOCK_CHEST( 20 | "LOCK_CHEST", 21 | "上锁", 22 | "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGFkOTQzZDA2MzM0N2Y5NWFiOWU5ZmE3NTc5MmRhODRlYzY2NWViZDIyYjA1MGJkYmE1MTlmZjdkYTYxZGIifX19" 23 | ), 24 | 25 | // 可用于防御塔 26 | KILL( 27 | "KILL", 28 | "杀戮机器", 29 | "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDZkYjEzN2EzNTY3OWJlYWY3OTAwNzBkMGM5Yzk2YzkwNjc2MjYwZWJjMDBkZDJjNzAwNTYyYTA5OWRiMDdjMCJ9fX0=" 30 | ), 31 | 32 | // 可用于防御塔 33 | REPAIR( 34 | "REPAIR", 35 | "修复机器", 36 | "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjJhMDJhM2JjNzk2MzZlYmNhOTZjYmFkYWY2NWNlNjNhZTcxZDcwYTc3MDg2ODNmODI1MzBhMjZjOWQ1MTczNSJ9fX0=" 37 | ), 38 | 39 | FARMER( 40 | "FARMER", 41 | "农夫", 42 | "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDY5YWM5NzZlZjQ4NDQ3Nzc2YmZmZmY3MGRmNjZjZWViNGE1ZGFjNTA1YjEzZjE3MjEyM2UxNGNkMzc1OTE4MSJ9fX0=" 43 | ), 44 | 45 | MINER( 46 | "MINER", 47 | "矿工", 48 | "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTdkYTdiYzJlN2Q0YjNkYjhiMzg4MTg3YWY2ODNmNTZhMTIxYzk2MWQ3ODdjNmY4NTFiYmI5Njc0YzkzNzQ2YiJ9fX0=" 49 | ), 50 | 51 | SOLDIER( 52 | "SOLDIER", 53 | "战士", 54 | "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmZjZjE0Mzk5NjIxMThlMWJkODdhYzM0YWMwZmRlZGFmYTIwZTZiOWU0N2MyYTEyNmVhY2FmOTgyNjdlNmIyNSJ9fX0=" 55 | ), 56 | 57 | TEST( 58 | "TEST", 59 | "TEST", 60 | "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHBzOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzE5NDZiMjc2OWJkMjM1ODQwZWUzZjgxOTljY2VkZjA4ZmZjNTc5ZDM2MmY2MDMwZTMwNmMzOTM1YzE1ZTVmN2YifX19" 61 | ), 62 | 63 | 64 | 65 | ; 66 | 67 | 68 | // CODE 69 | private String code; 70 | // 未解锁时显示的名称 name 71 | private String name; 72 | // GUI显示的材质 73 | private String textures; 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/enums/COIMultipleGameMode.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * 服务器状态枚举 8 | */ 9 | @Getter 10 | @AllArgsConstructor 11 | public enum COIMultipleGameMode { 12 | 13 | PVP("PVP","多人对抗"), 14 | PVPVE("PVPVE","对人对抗同时对抗怪物"), 15 | ; 16 | 17 | private String code; 18 | private String name; 19 | 20 | /** 21 | * 通过 code 获取枚举 22 | * @param code 23 | * @return 24 | */ 25 | public static COIMultipleGameMode parseCode(String code) { 26 | for (COIMultipleGameMode value : COIMultipleGameMode.values()) { 27 | if (value.code.equals(code)) { 28 | return value; 29 | } 30 | } 31 | return null; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/enums/COIPermissionType.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | @Getter 7 | @AllArgsConstructor 8 | public enum COIPermissionType { 9 | 10 | SKIN_PERMISSION("coi.skin.","皮肤系列权限"), 11 | 12 | ; 13 | 14 | 15 | // CODE 16 | private String code; 17 | // 名称 name 18 | private String name; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/enums/COIScoreType.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import net.kyori.adventure.text.format.NamedTextColor; 6 | import net.kyori.adventure.text.format.TextColor; 7 | import org.bukkit.Color; 8 | import org.bukkit.Material; 9 | 10 | /** 11 | * 队伍类型 12 | */ 13 | @Getter 14 | @AllArgsConstructor 15 | public enum COIScoreType { 16 | 17 | // 奖励 18 | KILL_ENTITY("击杀奖励", 19 | "小队玩家击杀敌方的人员产生的奖励", 20 | "击杀敌方单位获得奖励积分", 21 | 10), 22 | 23 | // 挖矿奖励 24 | GOOD_MINER("挖矿奖励", 25 | "小队玩家主动挖矿产生的奖励", 26 | "用镐子挖矿获得奖励积分", 27 | 2), 28 | 29 | DESTROY_BUILDING("拆除奖励", 30 | "小队玩家拆除敌方建筑产生的奖励", 31 | "拆除敌方建筑物获得奖励积分", 32 | 50), // 已完成埋点 33 | 34 | BUILD("建造奖励", 35 | "玩家建造任意一个建筑产生的奖励", 36 | "建造了一座建筑获得奖励积分", 37 | 50), // 已完成埋点 38 | 39 | DESTROY_SELF_BUILDING("拆除己方建筑惩罚", 40 | "玩家拆除任意一个己方建筑产生的惩罚", 41 | "拆除了一座己方建筑获得惩罚", 42 | -50), // 已完成埋点 43 | 44 | BUILD_INFRASTRUCTURE("建造基建奖励", 45 | "玩家建造任意基建产生的奖励", 46 | "建造了基建获得奖励积分", 47 | 2), // 已完成埋点 48 | 49 | UPGRADE_BUILDING("升级奖励", 50 | "玩家升级一座建筑产生的奖励", 51 | "升级了一座建筑获得奖励积分", 52 | 50), // 已完成埋点 53 | 54 | BEAT_TEAM("击败奖励", 55 | "小队玩家拆掉其他小队基地产生的奖励", 56 | "拆除敌方基地获得奖励积分", 57 | 1000), 58 | 59 | VICTORY("胜利奖", 60 | "小队获得最后的胜利", 61 | "小队获得最后的胜利!获得奖励积分", 62 | 2000), // 已完成埋点 63 | 64 | // MVP 65 | MVP("MVP", 66 | "全场表现最佳", 67 | "获得MVP奖励积分", 68 | 200), 69 | 70 | SVP("SVP", 71 | "败方队伍表现最佳", 72 | "获得SVP奖励积分", 73 | 200), 74 | ; 75 | 76 | // 积分变动类型名称 77 | private String name; 78 | // 备注 79 | private String remark; 80 | // 文本 81 | private String description; 82 | // 积分(可增可减) 83 | private double score; 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/enums/COIServerMode.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * 服务器状态枚举 8 | */ 9 | @Getter 10 | @AllArgsConstructor 11 | public enum COIServerMode { 12 | 13 | DEVELOP("develop","开发维护"), 14 | RELEASE("release","正常运营"), 15 | ; 16 | 17 | private String code; 18 | private String name; 19 | 20 | /** 21 | * 通过 code 获取枚举 22 | * @param code 23 | * @return 24 | */ 25 | public static COIServerMode parseCode(String code) { 26 | for (COIServerMode value : COIServerMode.values()) { 27 | if (value.code.equals(code)) { 28 | return value; 29 | } 30 | } 31 | return null; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/enums/COITeamType.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.enums; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import net.kyori.adventure.text.format.NamedTextColor; 6 | import net.kyori.adventure.text.format.TextColor; 7 | import org.bukkit.ChatColor; 8 | import org.bukkit.Color; 9 | import org.bukkit.Material; 10 | 11 | /** 12 | * 队伍类型 13 | */ 14 | @Getter 15 | @AllArgsConstructor 16 | public enum COITeamType { 17 | 18 | RED("RED","红队","&c", NamedTextColor.RED,NamedTextColor.RED,Material.RED_TERRACOTTA,Color.RED,12), 19 | YELLOW("YELLOW","黄队","&6",NamedTextColor.YELLOW,NamedTextColor.YELLOW,Material.YELLOW_TERRACOTTA,Color.YELLOW,14), 20 | GREEN("GREEN","绿队","&a",NamedTextColor.GREEN,NamedTextColor.GREEN,Material.GREEN_TERRACOTTA,Color.GREEN,16), 21 | BLUE("BLUE","蓝队","&b",NamedTextColor.BLUE,NamedTextColor.BLUE,Material.BLUE_TERRACOTTA,Color.BLUE,30), 22 | BLACK("BLACK","黑队","&8",NamedTextColor.DARK_GRAY,NamedTextColor.DARK_GRAY,Material.BLACK_TERRACOTTA,Color.BLACK,32), 23 | PURPLE("PURPLE","紫队","&5",NamedTextColor.LIGHT_PURPLE,NamedTextColor.LIGHT_PURPLE,Material.PURPLE_TERRACOTTA,Color.PURPLE,34), 24 | 25 | MONSTER("WHITE", "野怪", "&r", NamedTextColor.WHITE,NamedTextColor.WHITE, Material.WHITE_TERRACOTTA, Color.WHITE, -1); 26 | ; 27 | 28 | // CODE 29 | private final String code; 30 | // 小队名称 31 | private final String name; 32 | // 颜色代码 33 | private final String color; 34 | // NBT颜色 35 | private final TextColor textColor; 36 | // TEAM的颜色 37 | private final NamedTextColor namedTextColor; 38 | // 特殊颜色方块, 39 | private final Material blockColor; 40 | // 队伍皮革装备颜色 41 | private final Color leatherColor; 42 | // 在选择队伍界面的位置 43 | private final Integer slot; 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/enums/types/COIBuildingTypes.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.enums.types; 2 | 3 | import com.mcylm.coi.realm.enums.COIBuildingType; 4 | import com.mcylm.coi.realm.enums.COIUnlockType; 5 | 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | public class COIBuildingTypes { 10 | 11 | private static final Set values = new HashSet<>(); 12 | 13 | public static Set values() { 14 | return values; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/enums/types/COIUnlockTypes.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.enums.types; 2 | 3 | import com.mcylm.coi.realm.enums.COIUnlockType; 4 | 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | public class COIUnlockTypes { 9 | 10 | private static final Set values = new HashSet<>(); 11 | 12 | public static Set values() { 13 | return values; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/events/BuildingDamagedEvent.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.events; 2 | 3 | import com.mcylm.coi.realm.tools.building.COIBuilding; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import org.bukkit.block.Block; 7 | import org.bukkit.entity.Entity; 8 | import org.bukkit.entity.LivingEntity; 9 | import org.bukkit.event.Event; 10 | import org.bukkit.event.HandlerList; 11 | 12 | @Data 13 | @AllArgsConstructor 14 | public class BuildingDamagedEvent extends Event { 15 | 16 | private static final HandlerList HANDLERS = new HandlerList(); 17 | 18 | // 被攻击的建筑 19 | private COIBuilding building; 20 | 21 | // 被攻击的方块 22 | private Block attackedBlock; 23 | 24 | // 攻击者 25 | private Entity entity; 26 | 27 | @Override 28 | public HandlerList getHandlers() { 29 | return HANDLERS; 30 | } 31 | 32 | public static HandlerList getHandlerList() { 33 | return HANDLERS; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/events/BuildingDestroyedEvent.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.events; 2 | 3 | import com.mcylm.coi.realm.tools.building.COIBuilding; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import org.bukkit.entity.Entity; 7 | import org.bukkit.event.Event; 8 | import org.bukkit.event.HandlerList; 9 | 10 | @Data 11 | @AllArgsConstructor 12 | public class BuildingDestroyedEvent extends Event { 13 | 14 | private static final HandlerList HANDLERS = new HandlerList(); 15 | 16 | // 被摧毁的建筑 17 | private COIBuilding building; 18 | 19 | @Override 20 | public HandlerList getHandlers() { 21 | return HANDLERS; 22 | } 23 | 24 | public static HandlerList getHandlerList() { 25 | return HANDLERS; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/events/BuildingTouchEvent.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.events; 2 | 3 | import com.mcylm.coi.realm.tools.building.COIBuilding; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import org.bukkit.entity.Entity; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.event.Event; 9 | import org.bukkit.event.HandlerList; 10 | 11 | @Data 12 | @AllArgsConstructor 13 | public class BuildingTouchEvent extends Event { 14 | 15 | private static final HandlerList HANDLERS = new HandlerList(); 16 | 17 | // 被点击的建筑 18 | private COIBuilding building; 19 | 20 | // 点击的人 21 | private Player player; 22 | 23 | @Override 24 | public HandlerList getHandlers() { 25 | return HANDLERS; 26 | } 27 | 28 | public static HandlerList getHandlerList() { 29 | return HANDLERS; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/events/GameStatusEvent.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.events; 2 | 3 | import com.mcylm.coi.realm.enums.COIGameStatus; 4 | import lombok.Data; 5 | import org.bukkit.event.Event; 6 | import org.bukkit.event.HandlerList; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | @Data 10 | public class GameStatusEvent extends Event { 11 | 12 | private static final HandlerList HANDLERS = new HandlerList(); 13 | 14 | // 最新的游戏状态 15 | private COIGameStatus status; 16 | 17 | public GameStatusEvent(COIGameStatus status) { 18 | this.status = status; 19 | } 20 | 21 | @Override 22 | public HandlerList getHandlers() { 23 | return HANDLERS; 24 | } 25 | 26 | public static HandlerList getHandlerList() { 27 | return HANDLERS; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/gui/ChooseTeamGUI.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.gui; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.enums.COITeamType; 5 | import com.mcylm.coi.realm.tools.team.impl.COITeam; 6 | import com.mcylm.coi.realm.utils.LoggerUtils; 7 | import me.lucko.helper.item.ItemStackBuilder; 8 | import me.lucko.helper.menu.Gui; 9 | import me.lucko.helper.menu.scheme.MenuPopulator; 10 | import me.lucko.helper.menu.scheme.MenuScheme; 11 | import org.bukkit.entity.Player; 12 | 13 | public class ChooseTeamGUI extends Gui { 14 | 15 | // 物品排列方式 16 | private static final MenuScheme BUTTONS = new MenuScheme() 17 | .mask("000000000") 18 | .mask("001010100") 19 | .mask("000000000") 20 | .mask("001010100") 21 | .mask("000000000"); 22 | 23 | public ChooseTeamGUI(Player player) { 24 | super(player, 5, "&c&l请选择你的小队"); 25 | } 26 | 27 | @Override 28 | public void redraw() { 29 | 30 | // 放置按钮 31 | MenuPopulator populator = BUTTONS.newPopulator(this); 32 | for (COITeam team : Entry.getGame().getTeams()) { 33 | if (team.getType() == COITeamType.MONSTER) { 34 | continue; 35 | } 36 | populator.accept(ItemStackBuilder.of(team.getType().getBlockColor()) 37 | .name(team.getType().getColor() + team.getType().getName()) 38 | .amount(getChooseTeamGUIPeopleAmount(team)) 39 | .lore("") 40 | .lore("&f> &a人数: &c"+team.getPlayers().size() + "/" +Entry.MAX_GROUP_PLAYERS) 41 | .lore("&f> &a成员:") 42 | .lore(team.getPlayerListName()) 43 | .lore("") 44 | .lore("&f> &7点击加入当前小队") 45 | .build(() -> { 46 | // 点击时触发下面的方法 47 | boolean join = team.join(getPlayer()); 48 | if(join){ 49 | LoggerUtils.sendMessage("&7加入 "+team.getType().getColor() + team.getType().getName()+" &7成功",getPlayer()); 50 | }else{ 51 | LoggerUtils.sendMessage("&c当前小队已满人,无法选择该小队",getPlayer()); 52 | } 53 | redraw(); 54 | })); 55 | } 56 | 57 | } 58 | 59 | /** 60 | * 获取选择队伍GUI的人数数量 61 | * @return 62 | */ 63 | private static int getChooseTeamGUIPeopleAmount(COITeam team){ 64 | int size = team.getPlayers().size(); 65 | 66 | if(size == 0) { 67 | size = 1; 68 | } 69 | 70 | return size; 71 | } 72 | } -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/gui/ForgeGUI.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.gui; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.enums.COIGameStatus; 5 | import com.mcylm.coi.realm.item.COICustomItem; 6 | import com.mcylm.coi.realm.tools.building.COIBuilding; 7 | import com.mcylm.coi.realm.tools.team.impl.COITeam; 8 | import com.mcylm.coi.realm.utils.GUIUtils; 9 | import com.mcylm.coi.realm.utils.InventoryUtils; 10 | import com.mcylm.coi.realm.utils.LoggerUtils; 11 | import com.mcylm.coi.realm.utils.TeamUtils; 12 | import me.lucko.helper.item.ItemStackBuilder; 13 | import me.lucko.helper.menu.Item; 14 | import me.lucko.helper.menu.paginated.PaginatedGuiBuilder; 15 | import org.bukkit.Material; 16 | import org.bukkit.entity.Player; 17 | import org.bukkit.inventory.ItemStack; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | 23 | public class ForgeGUI { 24 | 25 | /** 26 | * 创建铁匠铺GUI 27 | * @param p 需要打开GUI的玩家 28 | * @param building 铁匠铺 29 | */ 30 | public ForgeGUI(Player p,COIBuilding building) { 31 | 32 | COITeam team = TeamUtils.getTeamByPlayer(p); 33 | 34 | // 未加入小队的,还有等待中的时候,都打开选队GUI 35 | if (team == null || Entry.getGame().getStatus().equals(COIGameStatus.WAITING)) { 36 | LoggerUtils.sendMessage("请选择你要加入的小队", p); 37 | ChooseTeamGUI chooseTeamGUI = new ChooseTeamGUI(p); 38 | chooseTeamGUI.open(); 39 | return; 40 | } 41 | 42 | PaginatedGuiBuilder builder = PaginatedGuiBuilder.create(); 43 | 44 | builder.title("&9&l选择你要打造的装备"); 45 | builder.previousPageSlot(49); 46 | builder.nextPageSlot(51); 47 | builder.nextPageItem((pageInfo) -> ItemStackBuilder.of(Material.ARROW).name("&a下一页").build()); 48 | builder.previousPageItem((pageInfo) -> ItemStackBuilder.of(Material.ARROW).name("&a上一页").build()); 49 | 50 | builder.build(p, paginatedGui -> { 51 | List items = new ArrayList<>(); 52 | 53 | for (COICustomItem customItem : Entry.getInstance().getCustomItemManager().getCustomItems()) { 54 | 55 | // 物品模型 56 | ItemStack item = customItem.getItemStack(); 57 | 58 | List lores = List.copyOf(item.getLore()); 59 | 60 | if (!customItem.shopSettings().showInShop()) { 61 | continue; 62 | } 63 | 64 | // 判断是否达到解锁条件 65 | if(COICustomItem.ShopSettings.checkUnlock(team, customItem)){ 66 | 67 | items.add(ItemStackBuilder.of(item.clone()) 68 | .name(customItem.getName()) 69 | .amount(1) 70 | .lore("") 71 | .lore("&f> &a单价/数量: &c" + customItem.shopSettings().price()+"&7/"+ customItem.shopSettings().num() +"个") 72 | .lore("&f> &a背包携带: &c" + building.getPlayerHadResource(p)) 73 | .lore("&f> &a介绍:") 74 | .lore(lores) 75 | .lore("") 76 | .lore("&f> &a&l点击进行打造") 77 | .build(() -> { 78 | // 点击时触发下面的方法 79 | 80 | // 扣除资源,并交付道具 81 | boolean b = InventoryUtils.deductionResources(p, customItem.shopSettings().price()); 82 | 83 | if(b){ 84 | // 扣除成功 85 | // 交付物品 86 | ItemStack propItem = customItem.getItemStack(); 87 | 88 | propItem.setAmount(customItem.shopSettings().num()); 89 | p.getInventory().addItem(propItem); 90 | LoggerUtils.sendMessage("物品打造完成!", p); 91 | 92 | }else{ 93 | LoggerUtils.sendMessage("&c背包内的资源不够!", p); 94 | paginatedGui.close(); 95 | } 96 | 97 | })); 98 | }else{ 99 | // 不满足解锁条件 100 | 101 | ItemStack itemType = new ItemStack(Material.CHEST); 102 | 103 | items.add(ItemStackBuilder.of(itemType.clone()) 104 | .name(customItem.getName()+" &c尚未解锁") 105 | .amount(1) 106 | .lore("") 107 | .lore("&f> &a解锁条件:") 108 | .lore(GUIUtils.autoLineFeed("建筑等级达到:"+ customItem.shopSettings().buildingLevel())) 109 | .lore("") 110 | .lore("&f> &a&l快去升级吧") 111 | .build(paginatedGui::close)); 112 | 113 | } 114 | } 115 | return items; 116 | }).open(); 117 | 118 | 119 | 120 | 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/gui/GuiBuilder/COIPaginatedGui.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.gui.GuiBuilder; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.google.common.collect.Lists; 5 | import java.util.ArrayList; 6 | import java.util.Collection; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | import java.util.function.Function; 10 | 11 | import com.mcylm.coi.realm.gui.SkinGUI; 12 | import com.mcylm.coi.realm.gui.SkinTypeGUI; 13 | import me.lucko.helper.item.ItemStackBuilder; 14 | import me.lucko.helper.menu.Gui; 15 | import me.lucko.helper.menu.Item; 16 | import me.lucko.helper.menu.Slot; 17 | import me.lucko.helper.menu.paginated.PageInfo; 18 | import me.lucko.helper.menu.paginated.PaginatedGui; 19 | import me.lucko.helper.menu.paginated.PaginatedGuiBuilder; 20 | import me.lucko.helper.menu.scheme.MenuScheme; 21 | import me.lucko.helper.utils.annotation.NonnullByDefault; 22 | import org.bukkit.entity.Player; 23 | import org.bukkit.inventory.ItemStack; 24 | 25 | public class COIPaginatedGui extends Gui { 26 | 27 | private final MenuScheme scheme; 28 | private final List itemSlots; 29 | private final int nextPageSlot; 30 | private final int previousPageSlot; 31 | private final int customSlot; 32 | private final Function nextPageItem; 33 | private final Function previousPageItem; 34 | private final Function customItem; 35 | private List content; 36 | private int page; 37 | 38 | public COIPaginatedGui(Function> content, Player player, COIPageGuiBuilder model) { 39 | super(player, model.getLines(), model.getTitle()); 40 | this.content = ImmutableList.copyOf((Collection)content.apply(this)); 41 | this.page = 1; 42 | this.scheme = model.getScheme(); 43 | this.itemSlots = ImmutableList.copyOf(model.getItemSlots()); 44 | this.nextPageSlot = model.getNextPageSlot(); 45 | this.previousPageSlot = model.getPreviousPageSlot(); 46 | this.customSlot = model.getCustomSlot(); 47 | this.nextPageItem = model.getNextPageItem(); 48 | this.previousPageItem = model.getPreviousPageItem(); 49 | this.customItem = model.getCustomItem(); 50 | } 51 | 52 | public void redraw() { 53 | this.scheme.apply(this); 54 | List slots = new ArrayList(this.itemSlots); 55 | List> pages = Lists.partition(this.content, slots.size()); 56 | if (this.page < 1) { 57 | this.page = 1; 58 | } else if (this.page > pages.size()) { 59 | this.page = Math.max(1, pages.size()); 60 | } 61 | 62 | List page = pages.isEmpty() ? new ArrayList() : (List)pages.get(this.page - 1); 63 | Slot slot; 64 | 65 | this.setItem(this.previousPageSlot, ItemStackBuilder.of((ItemStack)this.previousPageItem.apply(PageInfo.create(this.page, pages.size()))).build(() -> { 66 | --this.page; 67 | this.redraw(); 68 | })); 69 | 70 | this.setItem(this.nextPageSlot, ItemStackBuilder.of((ItemStack)this.nextPageItem.apply(PageInfo.create(this.page, pages.size()))).build(() -> { 71 | ++this.page; 72 | this.redraw(); 73 | })); 74 | 75 | this.setItem(this.customSlot,ItemStackBuilder.of((ItemStack)this.customItem.apply(PageInfo.create(this.page, pages.size()))).build(() -> { 76 | SkinTypeGUI skinTypeGUI = new SkinTypeGUI(getPlayer()); 77 | skinTypeGUI.open(); 78 | })); 79 | 80 | if (!this.isFirstDraw()) { 81 | slots.forEach(this::removeItem); 82 | } 83 | 84 | Iterator var7 = ((List)page).iterator(); 85 | 86 | while(var7.hasNext()) { 87 | Item item = (Item)var7.next(); 88 | int index = (Integer)slots.remove(0); 89 | this.setItem(index, item); 90 | } 91 | 92 | } 93 | 94 | public void updateContent(List content) { 95 | this.content = ImmutableList.copyOf(content); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/gui/SkinTypeGUI.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.gui; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.enums.COITeamType; 5 | import com.mcylm.coi.realm.enums.types.COIBuildingTypes; 6 | import com.mcylm.coi.realm.tools.building.COIBuilding; 7 | import com.mcylm.coi.realm.tools.team.impl.COITeam; 8 | import com.mcylm.coi.realm.utils.LoggerUtils; 9 | import me.lucko.helper.item.ItemStackBuilder; 10 | import me.lucko.helper.menu.Gui; 11 | import me.lucko.helper.menu.scheme.MenuPopulator; 12 | import me.lucko.helper.menu.scheme.MenuScheme; 13 | import org.bukkit.entity.Player; 14 | import org.bukkit.inventory.ItemStack; 15 | 16 | public class SkinTypeGUI extends Gui { 17 | 18 | // 物品排列方式 19 | private static final MenuScheme BUTTONS = new MenuScheme() 20 | .mask("111111111") 21 | .mask("111111111") 22 | .mask("111111111"); 23 | 24 | public SkinTypeGUI(Player player) { 25 | super(player, 3, "&c&l请选择皮肤分类"); 26 | } 27 | 28 | @Override 29 | public void redraw() { 30 | 31 | // 放置按钮 32 | MenuPopulator populator = BUTTONS.newPopulator(this); 33 | for (COIBuilding building : Entry.getInstance().getBuildingManager().getAllBuildingTemplates()) { 34 | 35 | if(building.getConfig().isShowInMenu()){ 36 | ItemStack item = building.getType().getItemType(); 37 | 38 | populator.accept(ItemStackBuilder.of(item.clone()) 39 | .name(building.getType().getName()) 40 | .amount(1) 41 | .lore("") 42 | .lore("&f点击查看该建筑的全部皮肤") 43 | .build(() -> { 44 | new SkinGUI(getPlayer(),building.getType()); 45 | })); 46 | } 47 | 48 | } 49 | 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/item/impl/tools/COIRocket.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.item.impl.tools; 2 | 3 | import com.mcylm.coi.realm.utils.InventoryUtils; 4 | import com.mcylm.coi.realm.utils.LoggerUtils; 5 | import lombok.Getter; 6 | import org.bukkit.Location; 7 | import org.bukkit.Particle; 8 | import org.bukkit.Sound; 9 | import org.bukkit.entity.Player; 10 | 11 | /** 12 | * 鞘翅推进器 13 | * 利用击退的原理来实现助推效果 14 | */ 15 | public class COIRocket { 16 | 17 | // 每次消耗资源 18 | @Getter 19 | private int cost = 8; 20 | // 每次飞行的距离 21 | @Getter 22 | private double distance = 1; 23 | @Getter 24 | private double springPower = 2; 25 | // 喷气 26 | public boolean jet(Player p){ 27 | 28 | boolean b = InventoryUtils.deductionResources(p, cost); 29 | 30 | if(!b){ 31 | LoggerUtils.sendActionbar(p,"&c背包内资源不足,无法起飞"); 32 | return false; 33 | } 34 | // 击退距离 35 | Location location = p.getLocation(); 36 | Location eyeLocation = p.getEyeLocation(); 37 | p.setVelocity(eyeLocation.getDirection().multiply(getSpringPower()).setY(getDistance())); 38 | p.playSound(location, Sound.ENTITY_BAT_TAKEOFF, 10, 0); 39 | p.getWorld().spawnParticle(Particle.CRIT, location, 15); 40 | 41 | return true; 42 | } 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/item/impl/tools/COITownPortal.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.item.impl.tools; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.tools.team.impl.COITeam; 5 | import com.mcylm.coi.realm.utils.LoggerUtils; 6 | import com.mcylm.coi.realm.utils.TeamUtils; 7 | import lombok.Getter; 8 | import org.bukkit.Location; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.scheduler.BukkitRunnable; 11 | 12 | /** 13 | * 回城卷轴 14 | */ 15 | public class COITownPortal { 16 | 17 | 18 | // 施法秒数 19 | @Getter 20 | private int counting = 10; 21 | 22 | /** 23 | * 回城 24 | * @param p 25 | */ 26 | public void back(Player p){ 27 | 28 | COITeam teamByPlayer = TeamUtils.getTeamByPlayer(p); 29 | 30 | if(teamByPlayer == null 31 | || teamByPlayer.isDefeat()){ 32 | LoggerUtils.sendActionbar(p,"&c回城失败,小队不存在!"); 33 | return; 34 | } 35 | 36 | new BukkitRunnable(){ 37 | 38 | // 血量缓存 39 | double initialHealth = p.getHealth(); 40 | // 缓存的位置 41 | Location initialLocation = p.getLocation(); 42 | int count = 0; 43 | @Override 44 | public void run() { 45 | 46 | if(count == counting){ 47 | 48 | 49 | Entry.runSync(new BukkitRunnable(){ 50 | 51 | @Override 52 | public void run() { 53 | p.teleport(teamByPlayer.getSpawner()); 54 | } 55 | }); 56 | 57 | cancel(); 58 | } 59 | 60 | // 实时血量 61 | double currentHealth = p.getHealth(); 62 | 63 | if(currentHealth < initialHealth){ 64 | LoggerUtils.sendActionbar(p,"&c回城过程中受到伤害被打断施法"); 65 | cancel(); 66 | }else{ 67 | int countDown = counting - count; 68 | LoggerUtils.sendActionbar(p,"&b回城施法中...还剩 &c"+countDown+" &b秒"); 69 | } 70 | 71 | Location location = p.getLocation(); 72 | 73 | if(location.distance(initialLocation) > 1){ 74 | // 移动距离超出允许的范围 75 | LoggerUtils.sendActionbar(p,"&c回城过程中移动被取消施法"); 76 | cancel(); 77 | } 78 | 79 | count++; 80 | } 81 | }.runTaskTimerAsynchronously(Entry.getInstance(),0,20); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/listener/MineralsBreakListener.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.listener; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.enums.COIGameStatus; 5 | import com.mcylm.coi.realm.enums.COIScoreType; 6 | import com.mcylm.coi.realm.model.COIBlock; 7 | import com.mcylm.coi.realm.tools.team.impl.COITeam; 8 | import com.mcylm.coi.realm.utils.LoggerUtils; 9 | import com.mcylm.coi.realm.utils.TeamUtils; 10 | import org.bukkit.Bukkit; 11 | import org.bukkit.GameMode; 12 | import org.bukkit.Location; 13 | import org.bukkit.Material; 14 | import org.bukkit.block.Block; 15 | import org.bukkit.block.BlockState; 16 | import org.bukkit.block.data.BlockData; 17 | import org.bukkit.event.EventHandler; 18 | import org.bukkit.event.Listener; 19 | import org.bukkit.event.block.BlockBreakEvent; 20 | import org.bukkit.event.player.PlayerInteractEvent; 21 | import org.bukkit.inventory.ItemStack; 22 | import org.bukkit.scheduler.BukkitRunnable; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | public class MineralsBreakListener implements Listener { 28 | 29 | /** 30 | * 玩家在游戏中挖矿的行为 31 | * @param event 32 | */ 33 | @EventHandler 34 | public void onMineralsBreak(BlockBreakEvent event){ 35 | 36 | // 创造模式可以随便搞 37 | if(event.getPlayer().getGameMode().equals(GameMode.CREATIVE)){ 38 | // 创造模式 39 | event.setCancelled(false); 40 | return; 41 | } 42 | 43 | if(Entry.getGame().getStatus().equals(COIGameStatus.GAMING)){ 44 | // 如果是游戏中 45 | 46 | if(null != TeamUtils.getTeamByPlayer(event.getPlayer())){ 47 | List blockMaterials = Entry.getInstance().getConfig().getStringList("miner.breaks"); 48 | 49 | if(!blockMaterials.isEmpty()){ 50 | 51 | boolean matched = false; 52 | 53 | // 判断是否属于矿工挖掘的方块类型 54 | for(String materialName : blockMaterials){ 55 | Material material = Material.getMaterial(materialName); 56 | 57 | if(event.getBlock().getType().equals(material)){ 58 | matched = true; 59 | 60 | // 挖矿奖励埋点 61 | COITeam team = TeamUtils.getTeamByPlayer(event.getPlayer()); 62 | if(team != null){ 63 | team.addScore(COIScoreType.GOOD_MINER,event.getPlayer()); 64 | } 65 | 66 | String dropMaterial = Entry.getInstance().getConfig().getString("game.building.material"); 67 | 68 | ItemStack item = new ItemStack(Material.getMaterial(dropMaterial)); 69 | // 正常5个,自然掉落1个,这4个 70 | item.setAmount(4); 71 | 72 | // 设置掉落 73 | event.getBlock().getLocation().getWorld() 74 | .dropItem(event.getBlock().getLocation(), 75 | item); 76 | 77 | } 78 | 79 | } 80 | 81 | if(!matched){ 82 | // 如果是非游戏允许挖掘的矿物,就禁止破坏方块 83 | event.setCancelled(true); 84 | } 85 | 86 | 87 | } 88 | } 89 | }else 90 | // 如果是非游戏模式下,禁止破坏方块 91 | event.setCancelled(true); 92 | 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/managers/COIBuildingManager.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.managers; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.enums.COIBuildingType; 5 | import com.mcylm.coi.realm.tools.building.COIBuilding; 6 | import com.mcylm.coi.realm.tools.building.config.BuildingConfig; 7 | 8 | import java.io.File; 9 | import java.io.FileReader; 10 | import java.io.FileWriter; 11 | import java.io.IOException; 12 | import java.util.ArrayList; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | public class COIBuildingManager { 18 | 19 | private final Map> buildingTypeClassMap = new HashMap<>(); 20 | private final List> buildingOrderList = new ArrayList<>(); 21 | 22 | private final Map buildingConfigMap = new HashMap<>(); 23 | 24 | // TODO: Reload 命令 25 | public void registerBuilding(COIBuildingType type, Class clazz) { 26 | buildingTypeClassMap.put(type, clazz); 27 | buildingOrderList.add(clazz); 28 | 29 | File folder = new File(Entry.getInstance().getDataFolder(), "buildings"); 30 | folder.mkdirs(); 31 | File configFile = new File(folder, type.getCode().toLowerCase() + ".json"); 32 | 33 | if (configFile.exists()) { 34 | try (FileReader reader = new FileReader(configFile)) { 35 | BuildingConfig config = Entry.GSON.fromJson(reader, BuildingConfig.class); 36 | buildingConfigMap.put(type, config); 37 | } catch (IOException e) { 38 | throw new RuntimeException(e); 39 | } 40 | } else { 41 | try { 42 | BuildingConfig config = getBuildingTemplateByType(type).getDefaultConfig(); 43 | buildingConfigMap.put(type, config); 44 | 45 | try (FileWriter writer = new FileWriter(configFile)) { 46 | writer.write(Entry.GSON.toJson(config)); 47 | } 48 | } catch (Exception e) { 49 | throw new RuntimeException(e); 50 | } 51 | } 52 | 53 | } 54 | 55 | public void unregisterBuilding(COIBuildingType type) { 56 | 57 | buildingOrderList.removeIf(c -> c.equals(buildingTypeClassMap.get(type))); 58 | buildingTypeClassMap.remove(type); 59 | buildingConfigMap.remove(type); 60 | } 61 | 62 | public COIBuilding getBuildingTemplateByType(COIBuildingType type) throws Exception { 63 | if (!buildingTypeClassMap.containsKey(type)) { 64 | throw new Exception("没有为类型找到对应的模板: " + type.getName()); 65 | } 66 | Class clazz = buildingTypeClassMap.get(type); 67 | COIBuilding building = clazz.getDeclaredConstructor().newInstance(); 68 | building.setType(type); 69 | if (buildingConfigMap.containsKey(type)) building.setConfig(buildingConfigMap.get(type)); 70 | 71 | return building; 72 | } 73 | 74 | public List getAllBuildingTemplates() { 75 | List result = new ArrayList<>(); 76 | for (Class clazz : buildingOrderList) { 77 | COIBuildingType type; 78 | try { 79 | type = getBuildingTypeFromClass(clazz); 80 | COIBuilding building = clazz.getDeclaredConstructor().newInstance(); 81 | building.setType(type); 82 | building.setConfig(buildingConfigMap.get(type)); 83 | result.add(building); 84 | } catch (Exception e) { 85 | throw new RuntimeException(e); 86 | } 87 | } 88 | return result; 89 | } 90 | 91 | private COIBuildingType getBuildingTypeFromClass(Class clazz) throws Exception { 92 | for (Map.Entry> entry : buildingTypeClassMap.entrySet()) { 93 | if (entry.getValue().equals(clazz)) { 94 | return entry.getKey(); 95 | } 96 | } 97 | throw new Exception("没有为类找到对应的类型: " + clazz.getSimpleName()); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/managers/CustomItemManager.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.managers; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.item.COICustomItem; 5 | import lombok.NonNull; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.Listener; 9 | import org.bukkit.event.block.Action; 10 | import org.bukkit.event.entity.EntityDamageByEntityEvent; 11 | import org.bukkit.event.player.PlayerDropItemEvent; 12 | import org.bukkit.event.player.PlayerInteractEvent; 13 | import org.bukkit.inventory.ItemStack; 14 | import org.bukkit.persistence.PersistentDataContainer; 15 | import org.bukkit.persistence.PersistentDataType; 16 | import org.jetbrains.annotations.NotNull; 17 | import org.jetbrains.annotations.Nullable; 18 | 19 | import java.util.ArrayList; 20 | import java.util.LinkedHashMap; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.function.Consumer; 24 | 25 | public class CustomItemManager implements Listener { 26 | private final Map items = new LinkedHashMap<>(); 27 | 28 | 29 | public void registerCustomItem(COICustomItem item) { 30 | if (this.items.containsKey(item.getNamespaceKey())) { 31 | return; 32 | } 33 | if (item.getEventListener() != null) { 34 | try { 35 | Listener listener = item.getEventListener().getConstructor(COICustomItem.class).newInstance(item); 36 | Entry.getInstance().getServer().getPluginManager().registerEvents(listener, Entry.getInstance()); 37 | } catch (Exception e) { 38 | e.printStackTrace(); 39 | } 40 | } 41 | this.items.put(item.getNamespaceKey(), item); 42 | } 43 | 44 | public @NonNull List getCustomItems() { 45 | return new ArrayList<>(this.items.values()); 46 | } 47 | 48 | 49 | public COICustomItem getCustomItem(@NonNull String namespaceKey) { 50 | 51 | return items.get(namespaceKey); 52 | } 53 | 54 | public ItemStack getItemStack(@NonNull String namespaceKey) { 55 | COICustomItem item = this.getCustomItem(namespaceKey); 56 | return item == null ? null : item.getItemStack(); 57 | } 58 | 59 | public @Nullable COICustomItem getCustomItemByItemStack(ItemStack itemStack) { 60 | @NotNull PersistentDataContainer pdc = itemStack.getItemMeta().getPersistentDataContainer(); 61 | 62 | if (!pdc.has(COICustomItem.COI_CUSTOM_ITEM_NAMESPACEDKEY)) { 63 | return null; 64 | } 65 | 66 | return this.items.get(pdc.get(COICustomItem.COI_CUSTOM_ITEM_NAMESPACEDKEY, PersistentDataType.STRING)); 67 | 68 | } 69 | 70 | 71 | 72 | @EventHandler 73 | public void playerInteractEvent(PlayerInteractEvent event) { 74 | if (event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getAction() == Action.RIGHT_CLICK_AIR) { 75 | if (event.getItem() == null) { 76 | return; 77 | } 78 | if (event.getItem().getItemMeta() == null) { 79 | return; 80 | } 81 | 82 | 83 | COICustomItem customItem = getCustomItemByItemStack(event.getItem()); 84 | 85 | if (customItem == null) { 86 | return; 87 | } 88 | Consumer consumer = customItem.itemUseEvent(); 89 | if (consumer != null) { 90 | consumer.accept(event); 91 | } 92 | } 93 | } 94 | 95 | @EventHandler 96 | public void entityDamageByEntityEvent(EntityDamageByEntityEvent event) { 97 | if (event.getDamager() instanceof Player player) { 98 | ItemStack item = player.getInventory().getItemInMainHand(); 99 | 100 | if (item.getItemMeta() == null) { 101 | return; 102 | } 103 | COICustomItem customItem = getCustomItemByItemStack(item); 104 | 105 | if (customItem == null) { 106 | return; 107 | } 108 | 109 | Consumer consumer = customItem.playerHitEntityEvent(); 110 | 111 | if (consumer != null) { 112 | consumer.accept(event); 113 | } 114 | 115 | } 116 | } 117 | 118 | @EventHandler 119 | public void playerDropItemEvent(PlayerDropItemEvent event) { 120 | 121 | if (event.getItemDrop().getItemStack().getItemMeta() == null) { 122 | return; 123 | } 124 | 125 | COICustomItem customItem = getCustomItemByItemStack(event.getItemDrop().getItemStack()); 126 | 127 | if (customItem == null) { 128 | return; 129 | } 130 | 131 | Consumer consumer = customItem.itemDropEvent(); 132 | if (consumer != null) { 133 | consumer.accept(event); 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/model/COIBlock.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.model; 2 | 3 | import com.mcylm.coi.realm.tools.building.COIBuilding; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.Setter; 7 | import lombok.ToString; 8 | import org.apache.commons.lang.StringUtils; 9 | import org.bukkit.Bukkit; 10 | import org.bukkit.block.Block; 11 | 12 | import java.io.Serializable; 13 | 14 | /** 15 | * 封装后的方块 16 | */ 17 | @Getter 18 | @Setter 19 | @RequiredArgsConstructor 20 | @ToString 21 | public class COIBlock implements Cloneable { 22 | 23 | private Integer x; 24 | private Integer y; 25 | private Integer z; 26 | 27 | private String blockData; 28 | private String material; 29 | private String world; 30 | 31 | public Block getBlock(){ 32 | 33 | if(StringUtils.isBlank(world)){ 34 | return null; 35 | } 36 | 37 | return Bukkit.getWorld(world).getBlockAt(x, y, z); 38 | } 39 | 40 | @Override 41 | public COIBlock clone() { 42 | try { 43 | return (COIBlock) super.clone(); 44 | } catch (CloneNotSupportedException e) { 45 | e.printStackTrace(); 46 | } 47 | return null; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/model/COIPaster.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.model; 2 | 3 | import com.mcylm.coi.realm.tools.handler.BlockPlaceCondition; 4 | import com.mcylm.coi.realm.tools.handler.BlockPlaceHandler; 5 | import lombok.*; 6 | import org.bukkit.Location; 7 | import org.bukkit.Material; 8 | 9 | import java.util.List; 10 | 11 | 12 | @Getter @Setter @RequiredArgsConstructor @ToString 13 | @AllArgsConstructor 14 | public class COIPaster { 15 | 16 | // 是否已完成 17 | private boolean complete = false; 18 | 19 | // 每次建筑几个方块 20 | private int unit; 21 | 22 | // 几秒建筑一次 23 | private long interval; 24 | 25 | // 世界名称 26 | private String worldName; 27 | 28 | // 建筑基点位置 29 | private Location location; 30 | 31 | // 建筑基点位置 32 | private Location spawnLocation; 33 | 34 | // 建筑结构体 35 | private COIStructure structure; 36 | 37 | // 是否建造空气方块 38 | private boolean withAir = true; 39 | 40 | // 小队的特殊颜色方块替换 41 | private Material blockColor; 42 | 43 | // 建筑物生成的NPC创建工具 44 | private List npcCreators; 45 | 46 | // 替换方块时触发 47 | private BlockPlaceHandler handler; 48 | 49 | // 方块替换的条件 50 | private BlockPlaceCondition condition; 51 | 52 | public COIPaster(boolean complete, int unit, long interval, String worldName, Location location, Location spawnLocation, COIStructure structure, boolean withAir, Material blockColor, List npcCreators, BlockPlaceHandler handler) { 53 | this.complete = complete; 54 | this.unit = unit; 55 | this.interval = interval; 56 | this.worldName = worldName; 57 | this.location = location; 58 | this.spawnLocation = spawnLocation; 59 | this.structure = structure; 60 | this.withAir = withAir; 61 | this.blockColor = blockColor; 62 | this.npcCreators = npcCreators; 63 | this.handler = handler; 64 | this.condition = (b, coiBlock, material) -> true; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/model/COIPlayerScore.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.model; 2 | 3 | import com.mcylm.coi.realm.enums.COIScoreType; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.ToString; 7 | import org.bukkit.entity.Player; 8 | 9 | import java.time.LocalDateTime; 10 | import java.util.List; 11 | 12 | @Data 13 | @ToString 14 | public class COIPlayerScore { 15 | 16 | // 玩家名称 17 | private String player; 18 | 19 | // 总积分 20 | private double score; 21 | 22 | // 积分明细 23 | private List scoreList; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/model/COIPosition.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.model; 2 | 3 | import lombok.*; 4 | 5 | /** 6 | * 二维位置相对坐标系 7 | * 8 | */ 9 | @Getter @Setter @RequiredArgsConstructor @ToString 10 | public class COIPosition { 11 | 12 | // 第几行 13 | private Integer row; 14 | 15 | // 第几列 16 | private Integer column; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/model/COIScore.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.model; 2 | 3 | import com.mcylm.coi.realm.enums.COIScoreType; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.ToString; 7 | import org.bukkit.entity.Player; 8 | 9 | import java.time.LocalDateTime; 10 | 11 | @Data 12 | @AllArgsConstructor 13 | public class COIScore { 14 | 15 | // 积分变化类型 16 | private COIScoreType type; 17 | 18 | // 时间 19 | private LocalDateTime time; 20 | 21 | // 玩家 22 | private Player player; 23 | 24 | @Override 25 | public String toString() { 26 | 27 | String symbol = "+"; 28 | if(type.getScore() < 0){ 29 | symbol = ""; 30 | } 31 | 32 | return type.getDescription()+" &b"+symbol+type.getScore(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/model/COIScoreDetail.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.model; 2 | 3 | import com.mcylm.coi.realm.enums.COIScoreType; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.ToString; 7 | import org.bukkit.entity.Player; 8 | 9 | import java.time.LocalDateTime; 10 | 11 | @Data 12 | @AllArgsConstructor 13 | public class COIScoreDetail { 14 | 15 | // 积分类型 16 | private COIScoreType type; 17 | 18 | // 当前类型的总积分 19 | private double score; 20 | 21 | // 总次数 22 | private int count; 23 | 24 | @Override 25 | public String toString() { 26 | return type.getName()+" x"+count+" (奖励积分:"+score+")"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/model/COISkin.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.model; 2 | 3 | import com.mcylm.coi.realm.enums.COIBuildingType; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.Map; 9 | 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | @Data 13 | public class COISkin { 14 | 15 | // CODE 16 | private String code; 17 | // 皮肤名称 18 | private String name; 19 | // GUI模型 20 | private String material; 21 | // 玩家所需权限 22 | private String permission; 23 | // 皮肤所对应的建筑 24 | private String buildingTypeCode; 25 | // 建筑等级模板文件 26 | private Map buildingLevelStructure; 27 | // NPC的皮肤 28 | private String npcSkin; 29 | 30 | public Map getBuildingLevelStructure(){ 31 | 32 | String maxDesignSkinFile = ""; 33 | 34 | for(int i = 1; i <= 100; i++){ 35 | if(this.buildingLevelStructure.get(i) != null){ 36 | maxDesignSkinFile = this.buildingLevelStructure.get(i); 37 | }else{ 38 | this.buildingLevelStructure.put(i,maxDesignSkinFile); 39 | } 40 | } 41 | 42 | return this.buildingLevelStructure; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/model/COIStructure.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.model; 2 | 3 | import com.mcylm.coi.realm.utils.LocationUtils; 4 | import com.mcylm.coi.realm.utils.rotation.Rotation; 5 | import com.mcylm.coi.realm.utils.rotation.Vector2Int; 6 | import lombok.Getter; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.Setter; 9 | import lombok.ToString; 10 | import org.bukkit.Bukkit; 11 | import org.bukkit.block.data.BlockData; 12 | import org.bukkit.block.data.Directional; 13 | import org.bukkit.block.data.Rotatable; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | /** 19 | * 建筑结构 20 | */ 21 | @Getter @Setter @RequiredArgsConstructor @ToString 22 | 23 | public class COIStructure implements Cloneable { 24 | 25 | private String name; 26 | private String fileName; 27 | private Integer length; 28 | private Integer width; 29 | private Integer height; 30 | private List blocks; 31 | 32 | @Override 33 | public COIStructure clone() { 34 | try { 35 | COIStructure cloned = (COIStructure) super.clone(); 36 | List clonedBlocks = new ArrayList<>(); 37 | 38 | for (COIBlock block : this.blocks) { 39 | clonedBlocks.add(block.clone()); // ?? COIBlock ????????? clone ?? 40 | } 41 | 42 | cloned.blocks = clonedBlocks; 43 | return cloned; 44 | } catch (CloneNotSupportedException e) { 45 | throw new AssertionError("Cloning error: " + e.getMessage()); 46 | } 47 | } 48 | 49 | public void rotate(Rotation rotation) { 50 | 51 | 52 | for (COIBlock block : blocks) { 53 | int x = block.getX(); 54 | int z = block.getZ(); 55 | 56 | Vector2Int r = Vector2Int.of(x, z).rotate(rotation); 57 | int rX = r.getX(); 58 | int rZ = r.getZ(); 59 | 60 | block.setX(rX); 61 | block.setZ(rZ); 62 | BlockData data = Bukkit.createBlockData(block.getBlockData()); 63 | int rv = Math.round(Math.floorMod(rotation.getDegrees(), 360) / 90f); 64 | 65 | if (data instanceof Rotatable rotatable) { 66 | rotatable.setRotation(LocationUtils.rotateBlockFace(rotatable.getRotation(), rv, false)); 67 | } 68 | 69 | if (data instanceof Directional directional) { 70 | directional.setFacing(LocationUtils.rotateBlockFace(directional.getFacing(), rv, false)); 71 | } 72 | block.setBlockData(data.getAsString()); 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/model/COITurretLocation.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.model; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class COITurretLocation { 7 | private String world; 8 | private String locationX; 9 | private String locationY; 10 | private String locationZ; 11 | } -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/model/ClipboardLocation.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.model; 2 | 3 | import com.mcylm.coi.realm.model.COIStructure; 4 | import lombok.*; 5 | import org.bukkit.Location; 6 | 7 | @Getter @Setter @RequiredArgsConstructor @ToString 8 | public class ClipboardLocation { 9 | 10 | //选取的第一个点 11 | private Location firstPoint; 12 | //选取的第二个点 13 | private Location secondPoint; 14 | //COI结构体 15 | private COIStructure structure; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/player/COIPlayer.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.player; 2 | 3 | import com.mcylm.coi.realm.model.COISkin; 4 | import com.mcylm.coi.realm.player.settings.PlayerSettings; 5 | import com.mcylm.coi.realm.tools.attack.target.Target; 6 | import com.mcylm.coi.realm.tools.attack.team.AttackTeam; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | import org.bukkit.entity.Player; 10 | 11 | import javax.annotation.Nullable; 12 | import java.time.LocalDateTime; 13 | import java.util.*; 14 | 15 | public class COIPlayer { 16 | 17 | private final Player player; 18 | @Getter 19 | private Set selectedTargets = new HashSet<>(); 20 | 21 | @Getter 22 | private AttackTeam attackTeam; 23 | // 死亡次数 24 | @Setter 25 | @Getter 26 | private int deathCount = 0; 27 | 28 | // 是否死亡复活中 29 | @Setter 30 | @Getter 31 | private boolean death = false; 32 | 33 | // 上一次摧毁建筑的时间 34 | @Setter 35 | @Getter 36 | private LocalDateTime lastDamageBuilding; 37 | 38 | @Setter 39 | @Getter 40 | @Nullable 41 | private Target attackedTarget; 42 | 43 | @Getter 44 | private PlayerSettings settings = new PlayerSettings(); 45 | 46 | // 玩家已选择并使用的建筑皮肤 47 | @Setter 48 | @Getter 49 | private HashMap selectedSkins; 50 | 51 | 52 | public Player getBukkitPlayer() { 53 | return player; 54 | } 55 | 56 | public COIPlayer(Player player){ 57 | this.player = player; 58 | this.attackTeam = new AttackTeam().setCommander(player).setMembers(new ArrayList<>()); 59 | this.lastDamageBuilding = null; 60 | this.selectedSkins = new HashMap<>(); 61 | 62 | // TODO 玩家设置部分待开发 63 | } 64 | 65 | /** 66 | * 获取死亡复活时间 67 | * @return 68 | */ 69 | public int getResurrectionCountdown(){ 70 | 71 | if(deathCount >= 10){ 72 | return 10; 73 | }else{ 74 | if(deathCount < 5){ 75 | return 5; 76 | } 77 | return deathCount; 78 | } 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/player/settings/GoalSetting.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.player.settings; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.bukkit.event.EventPriority; 6 | 7 | @Getter 8 | @Setter 9 | public class GoalSetting { 10 | private int priority = 5; 11 | private boolean forceGather = false; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/player/settings/PlayerSettings.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.player.settings; 2 | 3 | import com.mcylm.coi.realm.enums.AttackGoalType; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | @Getter 11 | @Setter 12 | public class PlayerSettings { 13 | private Map goalSettings = new HashMap<>(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/runnable/AttackGoalTask.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.runnable; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.tools.attack.AttackGoal; 5 | import com.mcylm.coi.realm.tools.npc.impl.COIEntity; 6 | import lombok.Getter; 7 | import org.bukkit.scheduler.BukkitRunnable; 8 | 9 | import java.util.HashSet; 10 | 11 | public class AttackGoalTask { 12 | 13 | @Getter 14 | private static HashSet goalSet = new HashSet<>(); 15 | 16 | public static void runTask() { 17 | new BukkitRunnable() { 18 | @Override 19 | public void run() { 20 | new HashSet<>(goalSet).forEach(goal -> { 21 | if (!goal.isStop()) { 22 | if (goal.getExecutor() instanceof COIEntity entity) { 23 | if (!entity.isTooHungryToWork()) { 24 | goal.tick(); 25 | } 26 | } 27 | } 28 | }); 29 | } 30 | }.runTaskTimer(Entry.getInstance(), 1, 1); 31 | 32 | new BukkitRunnable() { 33 | @Override 34 | public void run() { 35 | new HashSet<>(goalSet).forEach(goal -> { 36 | if (!goal.isStop()) { 37 | if (goal.getExecutor() instanceof COIEntity entity) { 38 | if (!entity.isTooHungryToWork()) { 39 | goal.asyncTick(); 40 | } 41 | } 42 | } 43 | }); 44 | } 45 | }.runTaskTimerAsynchronously(Entry.getInstance(), 1, 1); 46 | 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/runnable/NpcAITask.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.runnable; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.tools.npc.AI; 5 | import lombok.Getter; 6 | import org.bukkit.scheduler.BukkitRunnable; 7 | 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | public class NpcAITask { 12 | 13 | @Getter 14 | private static Set aiSet = new HashSet<>(); 15 | 16 | public static void runTask(AI ai) { 17 | 18 | if (!aiSet.contains(ai)) { 19 | 20 | aiSet.add(ai); 21 | new BukkitRunnable() { 22 | @Override 23 | public void run() { 24 | if (!aiSet.contains(ai)) { 25 | this.cancel(); 26 | return; 27 | } 28 | if (ai.isRemoved()) { 29 | aiSet.remove(ai); 30 | return; 31 | } 32 | ai.move(); 33 | 34 | } 35 | }.runTaskTimer(Entry.getInstance(), 0, ai.delayTick()); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/runnable/TaskRunnable.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.runnable; 2 | 3 | import net.citizensnpcs.api.ai.tree.BehaviorStatus; 4 | import net.citizensnpcs.api.npc.BlockBreaker; 5 | import org.bukkit.Bukkit; 6 | 7 | public class TaskRunnable implements Runnable{ 8 | 9 | private int taskId; 10 | private final BlockBreaker breaker; 11 | 12 | public TaskRunnable(BlockBreaker breaker) { 13 | this.breaker = breaker; 14 | } 15 | 16 | public int getTaskId() { 17 | return taskId; 18 | } 19 | 20 | public void setTaskId(int taskId) { 21 | this.taskId = taskId; 22 | } 23 | 24 | @Override 25 | public void run() { 26 | if (breaker.run() != BehaviorStatus.RUNNING) { 27 | Bukkit.getScheduler().cancelTask(taskId); 28 | breaker.reset(); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/runnable/VeinGenerateTask.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.runnable; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.tools.map.COIVein; 5 | import lombok.Getter; 6 | import org.bukkit.scheduler.BukkitRunnable; 7 | 8 | import java.security.SecureRandom; 9 | import java.util.HashSet; 10 | import java.util.Set; 11 | 12 | public class VeinGenerateTask { 13 | @Getter 14 | private static Set tasks = new HashSet<>(); 15 | 16 | public static void runTask() { 17 | tasks.forEach(BukkitRunnable::cancel); 18 | tasks.clear(); 19 | SecureRandom random = new SecureRandom(); 20 | for (COIVein vein : Entry.getMapData().getVeins()) { 21 | if (random.nextDouble() < vein.getSpawnChance()) { 22 | tasks.add(vein.startGenerate()); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/runnable/api/GameTaskApi.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.runnable.api; 2 | 3 | public interface GameTaskApi { 4 | 5 | // 启动中 6 | void waiting(); 7 | 8 | // 游戏中 9 | void gaming(); 10 | 11 | // 结算中 12 | void stopping(); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/attack/AttackGoal.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.attack; 2 | 3 | import com.destroystokyo.paper.entity.ai.GoalType; 4 | import com.mcylm.coi.realm.enums.AttackGoalType; 5 | 6 | public interface AttackGoal { 7 | 8 | void start(); 9 | 10 | void tick(); 11 | 12 | void asyncTick(); 13 | 14 | void stop(); 15 | 16 | Commandable getExecutor(); 17 | boolean isStop(); 18 | 19 | AttackGoalType getType(); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/attack/Commandable.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.attack; 2 | 3 | 4 | import org.bukkit.entity.LivingEntity; 5 | 6 | public interface Commandable extends DamageableAI { 7 | 8 | void setCommander(LivingEntity entity); 9 | 10 | LivingEntity getCommander(); 11 | 12 | void setGoal(AttackGoal goal); 13 | 14 | AttackGoal getGoal(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/attack/DamageableAI.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.attack; 2 | 3 | import com.mcylm.coi.realm.tools.attack.target.Target; 4 | import com.mcylm.coi.realm.tools.npc.impl.COIEntity; 5 | import org.bukkit.Location; 6 | 7 | public interface DamageableAI { 8 | 9 | 10 | default boolean setTarget(Target target) { 11 | if (target == null) { 12 | setTargetDirectly(null); 13 | return true; 14 | } 15 | if (getTarget() == null || getTarget().isDead()) { 16 | setTargetDirectly(target); 17 | return true; 18 | } 19 | if (target.getTargetLevel() >= getTarget().getTargetLevel()) { 20 | setTargetDirectly(target); 21 | return true; 22 | } 23 | return false; 24 | } 25 | 26 | default COIEntity asEntity() { 27 | return (COIEntity) this; 28 | } 29 | void lookForEnemy(int radius); 30 | 31 | Target getTarget(); 32 | 33 | void setTargetDirectly(Target target); 34 | 35 | void damage(Target target, double damage, Location attackLocation); 36 | 37 | Location getLocation(); 38 | 39 | void findPath(Location location); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/attack/impl/FollowGoal.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.attack.impl; 2 | 3 | import com.mcylm.coi.realm.enums.AttackGoalType; 4 | import com.mcylm.coi.realm.tools.attack.Commandable; 5 | import com.mcylm.coi.realm.tools.npc.impl.COIEntity; 6 | import org.bukkit.Material; 7 | import org.bukkit.attribute.Attribute; 8 | import org.bukkit.entity.LivingEntity; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.inventory.ItemStack; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.HashMap; 14 | 15 | public class FollowGoal extends SimpleGoal { 16 | 17 | public FollowGoal(Commandable npc) { 18 | super(npc); 19 | } 20 | 21 | // 跟随范围,超出范围会跟上玩家 22 | private int maxRadius = 5; 23 | 24 | // 保持饥饿度到多少 25 | private int keepHunger = 20; 26 | 27 | // 每次投喂多少个 28 | private int feedNum = 2; 29 | 30 | // 2秒扣一次,避免给旋了 31 | private int skipFeedAction = 0; 32 | 33 | @Override 34 | public void tick() { 35 | Commandable npc = getExecutor(); 36 | 37 | if (npc.getTarget() == null && npc.getCommander() != null) { 38 | if (npc.getLocation() != null && npc.getLocation().distance(npc.getCommander().getLocation()) >= maxRadius) { 39 | npc.findPath(npc.getCommander().getLocation()); 40 | } 41 | } 42 | 43 | if (npc instanceof COIEntity entity) { 44 | if (entity.isAlive() && entity.getHunger() < keepHunger) { 45 | if (npc.getCommander() instanceof Player player) { 46 | 47 | if(skipFeedAction == 40){ 48 | skipFeedAction = 0; 49 | } 50 | 51 | if(skipFeedAction == 0){ 52 | @NotNull HashMap extra = player.getInventory().removeItem(new ItemStack(Material.BREAD, feedNum)); 53 | if (extra.isEmpty()) { 54 | entity.addItemToInventory(new ItemStack(Material.BREAD, feedNum)); 55 | } else { 56 | extra.values().forEach(item -> { 57 | if (feedNum - item.getAmount() > 0) { 58 | entity.addItemToInventory(new ItemStack(Material.BREAD, feedNum - item.getAmount())); 59 | } 60 | }); 61 | } 62 | } 63 | 64 | skipFeedAction++; 65 | 66 | } 67 | } 68 | } 69 | 70 | getExecutor().lookForEnemy(maxRadius); 71 | } 72 | 73 | @Override 74 | public void asyncTick() { 75 | 76 | } 77 | 78 | @Override 79 | public AttackGoalType getType() { 80 | return AttackGoalType.FOLLOW; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/attack/impl/GatherGoal.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.attack.impl; 2 | 3 | import com.mcylm.coi.realm.enums.AttackGoalType; 4 | import com.mcylm.coi.realm.tools.attack.Commandable; 5 | 6 | public class GatherGoal extends SimpleGoal { 7 | 8 | private final boolean force; 9 | 10 | public GatherGoal(Commandable npc, boolean force) { 11 | super(npc); 12 | this.force = force; 13 | } 14 | 15 | @Override 16 | public void tick() { 17 | Commandable npc = getExecutor(); 18 | if (npc.getTarget() != null && force) { 19 | npc.setTarget(null); 20 | } 21 | 22 | if (npc.getTarget() == null && npc.getCommander() != null) { 23 | if (npc.getLocation() != null && npc.getLocation().distance(npc.getCommander().getLocation()) >= 10) { 24 | npc.findPath(npc.getCommander().getLocation()); 25 | } 26 | } 27 | } 28 | 29 | @Override 30 | public void asyncTick() { 31 | 32 | } 33 | 34 | @Override 35 | public AttackGoalType getType() { 36 | return AttackGoalType.GATHER; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/attack/impl/GuardGoal.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.attack.impl; 2 | 3 | import com.mcylm.coi.realm.enums.AttackGoalType; 4 | import com.mcylm.coi.realm.tools.attack.Commandable; 5 | import org.bukkit.Location; 6 | 7 | public class GuardGoal extends SimpleGoal { 8 | 9 | private Location point; 10 | private int maxRadius = 20; 11 | 12 | public GuardGoal(Commandable npc, Location point) { 13 | super(npc); 14 | this.point = point; 15 | } 16 | 17 | 18 | @Override 19 | public void tick() { 20 | Commandable npc = getExecutor(); 21 | if (npc.getLocation() == null) return; 22 | if (npc.getTarget() == null && npc.getLocation().distance(point) > 8) { 23 | npc.findPath(point); 24 | } 25 | 26 | if (npc.getTarget() != null && npc.getLocation().distance(npc.getTarget().getTargetLocation()) > maxRadius) { 27 | npc.setTarget(null); 28 | npc.findPath(point); 29 | } 30 | getExecutor().lookForEnemy(maxRadius); 31 | 32 | } 33 | 34 | @Override 35 | public void asyncTick() { 36 | 37 | } 38 | 39 | @Override 40 | public AttackGoalType getType() { 41 | return AttackGoalType.GUARD; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/attack/impl/PatrolGoal.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.attack.impl; 2 | 3 | import com.mcylm.coi.realm.enums.AttackGoalType; 4 | import com.mcylm.coi.realm.tools.attack.Commandable; 5 | import com.mcylm.coi.realm.tools.npc.impl.COIEntity; 6 | import org.bukkit.Location; 7 | 8 | import java.util.Random; 9 | 10 | 11 | 12 | public class PatrolGoal extends SimpleGoal { 13 | 14 | int moveAroundTick = 0; 15 | 16 | // 最大巡逻范围 17 | int maxRadius = 20; 18 | // 巡逻中心位置 19 | Location point; 20 | public PatrolGoal(Commandable npc) { 21 | super(npc); 22 | if (npc.getLocation() != null) { 23 | point = npc.getLocation(); 24 | } else if (npc instanceof COIEntity entity) { 25 | point = entity.getCoiNpc().getSpawnLocation(); 26 | } 27 | } 28 | 29 | public PatrolGoal(Commandable npc, int maxRadius, Location point) { 30 | super(npc); 31 | this.maxRadius = maxRadius; 32 | this.point = point; 33 | } 34 | 35 | 36 | @Override 37 | public void tick() { 38 | 39 | 40 | Random random = new Random(); 41 | Commandable npc = getExecutor(); 42 | if (npc.getLocation() == null) return; 43 | if (npc.getLocation().distance(point) > maxRadius) { 44 | npc.findPath(point); 45 | npc.setTarget(null); 46 | } 47 | if (moveAroundTick++ > 60 + random.nextInt(-10, 60)) { 48 | moveAroundTick = 0; 49 | if (npc.getTarget() == null) { 50 | Location to = npc.getLocation().clone().add(random.nextDouble(-16, 16), 0, random.nextDouble(-16, 16)); 51 | if (to.distance(point) > maxRadius) { 52 | return; 53 | } 54 | Location finalTo = to.getWorld().getHighestBlockAt(to).getLocation(); 55 | npc.findPath(finalTo); 56 | } 57 | } 58 | 59 | getExecutor().lookForEnemy(-1); 60 | 61 | } 62 | 63 | @Override 64 | public void asyncTick() { 65 | 66 | } 67 | 68 | 69 | @Override 70 | public AttackGoalType getType() { 71 | return AttackGoalType.PATROL; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/attack/impl/SimpleGoal.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.attack.impl; 2 | 3 | import com.mcylm.coi.realm.enums.AttackGoalType; 4 | import com.mcylm.coi.realm.tools.attack.AttackGoal; 5 | import com.mcylm.coi.realm.tools.attack.Commandable; 6 | import lombok.AllArgsConstructor; 7 | import org.bukkit.Location; 8 | 9 | public abstract class SimpleGoal implements AttackGoal { 10 | 11 | private Commandable npc; 12 | private boolean stop; 13 | 14 | public SimpleGoal(Commandable npc) { 15 | this.npc = npc; 16 | this.stop = true; 17 | } 18 | 19 | @Override 20 | public void start() { 21 | stop = false; 22 | } 23 | 24 | 25 | @Override 26 | public void stop() { 27 | 28 | this.stop = true; 29 | } 30 | 31 | @Override 32 | public Commandable getExecutor() { 33 | return npc; 34 | } 35 | 36 | @Override 37 | public boolean isStop() { 38 | return stop; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/attack/impl/TeamFollowGoal.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.attack.impl; 2 | 3 | import com.mcylm.coi.realm.enums.AttackGoalType; 4 | import com.mcylm.coi.realm.tools.attack.Commandable; 5 | import com.mcylm.coi.realm.tools.attack.team.AttackTeam; 6 | import com.mcylm.coi.realm.tools.npc.impl.COIEntity; 7 | import org.bukkit.Material; 8 | import org.bukkit.entity.LivingEntity; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.inventory.ItemStack; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.HashMap; 14 | 15 | 16 | public class TeamFollowGoal extends SimpleGoal { 17 | 18 | private AttackTeam team; 19 | private LivingEntity followingEntity; 20 | 21 | // 保持饥饿度到多少 22 | private int keepHunger = 20; 23 | 24 | // 每次投喂多少个 25 | private int feedNum = 2; 26 | 27 | // 2秒扣一次,避免给旋了 28 | private int skipFeedAction = 0; 29 | 30 | // 最大的半径范围 31 | private int maxRadius = 30; 32 | 33 | public TeamFollowGoal(Commandable npc, AttackTeam team) { 34 | super(npc); 35 | this.team = team; 36 | } 37 | 38 | @Override 39 | public void tick() { 40 | 41 | Commandable npc = getExecutor(); 42 | 43 | 44 | if (npc.getLocation() == null && followingEntity != null) { 45 | quitTeam(); 46 | return; 47 | } 48 | 49 | if (npc.getLocation().distance(team.getCommander().getLocation()) > maxRadius * 1.4) { 50 | quitTeam(); 51 | return; 52 | } 53 | 54 | // int index = team.getMembers().indexOf((COIEntity) npc); 55 | 56 | boolean needFollow; 57 | if (npc.getTarget() == null && followingEntity != null && npc.getLocation().distance(followingEntity.getLocation()) > 2) { 58 | needFollow = true; 59 | } else { 60 | needFollow = false; 61 | } 62 | if (followingEntity != null && npc.getLocation().distance(followingEntity.getLocation()) > maxRadius) { 63 | needFollow = true; 64 | } 65 | if (needFollow) { 66 | npc.setTarget(null); 67 | if (npc.getLocation() != null && npc.getLocation().distance(npc.getCommander().getLocation()) >= 3) { 68 | npc.findPath(followingEntity.getLocation()); 69 | } 70 | } 71 | 72 | 73 | COIEntity entity = (COIEntity) npc; 74 | if (entity.isAlive() && entity.getHunger() < keepHunger) { 75 | if (npc.getCommander() instanceof Player player) { 76 | 77 | if (skipFeedAction == 40) { 78 | skipFeedAction = 0; 79 | } 80 | 81 | if (skipFeedAction == 0) { 82 | @NotNull HashMap extra = player.getInventory().removeItem(new ItemStack(Material.BREAD, feedNum)); 83 | if (extra.isEmpty()) { 84 | entity.addItemToInventory(new ItemStack(Material.BREAD, feedNum)); 85 | } else { 86 | extra.values().forEach(item -> { 87 | if (feedNum - item.getAmount() > 0) { 88 | entity.addItemToInventory(new ItemStack(Material.BREAD, feedNum - item.getAmount())); 89 | } 90 | }); 91 | } 92 | } 93 | 94 | skipFeedAction++; 95 | 96 | } 97 | } 98 | 99 | getExecutor().lookForEnemy(maxRadius); 100 | 101 | } 102 | 103 | @Override 104 | public void asyncTick() { 105 | 106 | COIEntity entity = (COIEntity) getExecutor(); 107 | 108 | 109 | if (team.getCommander() instanceof Player player) { 110 | if (!player.isOnline()) { 111 | quitTeam(); 112 | } 113 | } 114 | 115 | int index = team.getMembers().indexOf(entity); 116 | if (index == -1) { 117 | quitTeam(); 118 | return; 119 | } 120 | if (index == 0) { 121 | followingEntity = team.getCommander(); 122 | } else { 123 | for (int i = index; i >= 0 ; i--) { 124 | COIEntity member = team.getMembers().get(i); 125 | if (member.isAlive() && member != this.getExecutor()) { 126 | followingEntity = (LivingEntity) team.getMembers().get(i).getNpc().getEntity(); 127 | break; 128 | } 129 | } 130 | } 131 | 132 | 133 | 134 | } 135 | 136 | @Override 137 | public AttackGoalType getType() { 138 | return AttackGoalType.TEAM_FOLLOW; 139 | } 140 | 141 | public void quitTeam() { 142 | 143 | if (getExecutor() instanceof COIEntity entity) { 144 | getExecutor().setGoal(new PatrolGoal(getExecutor())); 145 | getExecutor().getGoal().start(); 146 | team.getMembers().remove(entity); 147 | } 148 | } 149 | 150 | 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/attack/target/Target.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.attack.target; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | import lombok.Setter; 6 | import org.bukkit.Location; 7 | import org.bukkit.entity.Entity; 8 | import org.bukkit.entity.LivingEntity; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | @NoArgsConstructor 12 | public abstract class Target { 13 | 14 | @Getter 15 | @Setter 16 | private int targetLevel; 17 | 18 | public Target(int p) { 19 | this.targetLevel = p; 20 | } 21 | 22 | public abstract TargetType getType(); 23 | 24 | public abstract Location getTargetLocation(); 25 | 26 | public abstract boolean isDead(); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/attack/target/TargetType.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.attack.target; 2 | 3 | public enum TargetType { 4 | ENTITY, 5 | BUILDING, 6 | EMPTY 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/attack/target/impl/BuildingTarget.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.attack.target.impl; 2 | 3 | import com.mcylm.coi.realm.tools.attack.target.Target; 4 | import com.mcylm.coi.realm.tools.attack.target.TargetType; 5 | import com.mcylm.coi.realm.tools.building.COIBuilding; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | import org.bukkit.Location; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | @Getter 12 | @Setter 13 | 14 | public class BuildingTarget extends Target { 15 | 16 | private COIBuilding building; 17 | private Location location; 18 | 19 | public BuildingTarget(COIBuilding building, Location location, int p) { 20 | super(p); 21 | this.building = building; 22 | this.location = location; 23 | } 24 | 25 | @Override 26 | public TargetType getType() { 27 | return TargetType.BUILDING; 28 | } 29 | 30 | @Override 31 | public @NotNull Location getTargetLocation() { 32 | return location; 33 | } 34 | 35 | @Override 36 | public boolean isDead() { 37 | return !building.isAlive(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/attack/target/impl/EntityTarget.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.attack.target.impl; 2 | 3 | import com.mcylm.coi.realm.model.COINpc; 4 | import com.mcylm.coi.realm.tools.attack.target.Target; 5 | import com.mcylm.coi.realm.tools.attack.target.TargetType; 6 | import com.mcylm.coi.realm.tools.data.metadata.EntityData; 7 | import lombok.AllArgsConstructor; 8 | import lombok.Getter; 9 | import lombok.Setter; 10 | import org.bukkit.Location; 11 | import org.bukkit.entity.LivingEntity; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | @AllArgsConstructor 15 | @Getter 16 | @Setter 17 | public class EntityTarget extends Target { 18 | 19 | private LivingEntity entity; 20 | 21 | public EntityTarget(LivingEntity livingEntity, int p) { 22 | super(p); 23 | this.entity = livingEntity; 24 | 25 | } 26 | 27 | 28 | @Override 29 | public TargetType getType() { 30 | return TargetType.ENTITY; 31 | } 32 | 33 | @Override 34 | public @NotNull Location getTargetLocation() { 35 | return entity.getLocation(); 36 | } 37 | 38 | @Override 39 | public boolean isDead() { 40 | COINpc npc = EntityData.getNpcByEntity(entity); 41 | 42 | if (npc != null) { 43 | if (npc.getNpc().isRemoved()) { 44 | return true; 45 | } 46 | return !npc.getNpc().isAlive(); 47 | } 48 | return entity.isDead(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/attack/team/AttackTeam.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.attack.team; 2 | 3 | 4 | import com.mcylm.coi.realm.tools.npc.impl.COIEntity; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import lombok.experimental.Accessors; 8 | import org.bukkit.Location; 9 | import org.bukkit.entity.LivingEntity; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | // 怪物的战斗小队 15 | @Getter 16 | @Setter 17 | @Accessors(chain = true) 18 | public class AttackTeam { 19 | 20 | // 队长 21 | private LivingEntity commander; 22 | private Location target; 23 | // 队员 24 | List members = new ArrayList<>(); 25 | 26 | private Status status = Status.FREE; 27 | 28 | public enum Status { 29 | LOCK, 30 | FREE // 自由攻击 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/building/Builder.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.building; 2 | 3 | import com.mcylm.coi.realm.model.COIPaster; 4 | import org.bukkit.Material; 5 | import org.bukkit.block.Block; 6 | import org.bukkit.entity.Player; 7 | 8 | public interface Builder { 9 | 10 | //自动建造建筑 11 | void pasteStructure(COIPaster paste, COIBuilding building); 12 | 13 | //玩家自动建造建筑,并发送消息 14 | void pasteStructure(COIPaster paste, Player player, COIBuilding building); 15 | 16 | // 建造一个不归属COIBuilding的结构 17 | void pasteStructureWithoutBuilding(COIPaster paste, Player player); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/building/ConnectableBuild.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.building; 2 | 3 | import com.mcylm.coi.realm.tools.data.metadata.BuildData; 4 | import com.mcylm.coi.realm.utils.LocationUtils; 5 | import com.mcylm.coi.realm.utils.LoggerUtils; 6 | import lombok.Getter; 7 | import org.bukkit.Location; 8 | import org.bukkit.entity.Player; 9 | import org.bukkit.util.Vector; 10 | 11 | import java.util.HashSet; 12 | import java.util.List; 13 | import java.util.Set; 14 | 15 | @Deprecated 16 | public abstract class ConnectableBuild extends COIBuilding { 17 | 18 | @Getter 19 | protected Set alreadyConnected = new HashSet<>(); 20 | 21 | @Override 22 | public void buildSuccess(Location location, Player player) { 23 | 24 | setLocation(location); 25 | LoggerUtils.debug("self loc " + location); 26 | 27 | for (COIBuilding building : LocationUtils.getNearbyBuildings(location, getMaxLength())) { 28 | LoggerUtils.debug("find " + building.getLocation()); 29 | if (building instanceof ConnectableBuild connectableBuild) { 30 | 31 | if (!connectConditionsCheck(connectableBuild)) { 32 | continue; 33 | } 34 | Location[] points = getNearestConnectPoints(connectableBuild); 35 | 36 | if (alreadyConnected.size() < getMaxConnectBuild() && Math.abs((points[0].getY() - points[1].getY())) < 5) { 37 | LoggerUtils.debug("try connect"); 38 | if (alreadyConnected.contains(connectableBuild)) { 39 | continue; 40 | } 41 | if (connectableBuild.getAlreadyConnected().size() >= connectableBuild.getMaxConnectBuild()) { 42 | continue; 43 | } 44 | 45 | if (!connect(points[0], points[1])) return; 46 | alreadyConnected.add(connectableBuild); 47 | connectableBuild.getAlreadyConnected().add(this); 48 | 49 | LoggerUtils.debug("connected" + points[0] + " to " + points[1]); 50 | } 51 | } 52 | } 53 | } 54 | 55 | public int getMaxLength() { 56 | return 20; 57 | }; 58 | 59 | public boolean connect(Location start, Location end) { 60 | List locations = LocationUtils.line(start, end, getLineRate()); 61 | 62 | if (!connectLineCheck(locations)) { 63 | return false; 64 | } 65 | for (Location location : locations) { 66 | buildPoint(location, end.clone().subtract(start).toVector()); 67 | } 68 | return true; 69 | } 70 | 71 | public boolean connectLineCheck(List line) { 72 | for (Location point : line) { 73 | if (BuildData.getBuildingByBlock(point.getBlock()) != null) { 74 | return false; 75 | } 76 | } 77 | return true; 78 | } 79 | 80 | public boolean connectConditionsCheck(ConnectableBuild to) { 81 | 82 | Vector vectorAB = to.getLocation().clone().subtract(getLocation()).toVector(); 83 | 84 | for (ConnectableBuild build : getAlreadyConnected()) { 85 | Vector vectorAC = build.getLocation().clone().subtract(getLocation()).toVector(); 86 | if (vectorAC.angle(vectorAB) < Math.toRadians(15)) { 87 | return false; 88 | } 89 | } 90 | 91 | return to.getTeam() == getTeam(); 92 | } 93 | 94 | public abstract void buildPoint(Location point, Vector line); 95 | 96 | public List getConnectPoints() { 97 | return List.of(getLocation()); 98 | }; 99 | 100 | public Location[] getNearestConnectPoints(ConnectableBuild build) { 101 | Location[] points = new Location[2]; 102 | double min = 99999999; 103 | for (Location point1 : build.getConnectPoints()) { 104 | for (Location point2 : getConnectPoints()) { 105 | double distance = point1.distance(point2); 106 | if (distance < min) { 107 | points[0] = point1; 108 | points[1] = point2; 109 | min = distance; 110 | } 111 | } 112 | } 113 | return points; 114 | } 115 | 116 | @Override 117 | public void destroy(boolean effect) { 118 | super.destroy(effect); 119 | getAlreadyConnected().forEach(connectableBuild -> connectableBuild.getAlreadyConnected().remove(this)); 120 | getAlreadyConnected().clear(); 121 | } 122 | 123 | public abstract int getMaxConnectBuild(); 124 | 125 | public double getLineRate() { 126 | return 1; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/building/FloatableBuild.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.building; 2 | 3 | public abstract class FloatableBuild extends COIBuilding{ 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/building/config/BuildingConfig.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.building.config; 2 | 3 | import com.google.gson.JsonObject; 4 | import com.google.gson.annotations.SerializedName; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import lombok.experimental.Accessors; 8 | 9 | import java.util.Map; 10 | 11 | @Getter 12 | @Setter 13 | @Accessors(chain = true) 14 | public class BuildingConfig { 15 | 16 | public BuildingConfig() { 17 | showInMenu = true; 18 | this.maxLevel = 1; 19 | this.maxBuild = 1; 20 | this.consume = 16; 21 | this.structures = Map.of(); 22 | this.customOptions = new JsonObject(); 23 | } 24 | 25 | @SerializedName("show_in_menu") 26 | boolean showInMenu; 27 | 28 | @SerializedName("max_level") 29 | private int maxLevel; 30 | @SerializedName("max_build") 31 | private int maxBuild; 32 | private int consume; 33 | 34 | private Map structures; 35 | 36 | @SerializedName("custom_options") 37 | private JsonObject customOptions; 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/building/impl/COIAirRaid.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.building.impl; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.runnable.AirRaidTask; 5 | import com.mcylm.coi.realm.runnable.TurretTask; 6 | import com.mcylm.coi.realm.tools.building.COIBuilding; 7 | import com.mcylm.coi.realm.tools.building.config.BuildingConfig; 8 | import com.mcylm.coi.realm.utils.GUIUtils; 9 | import lombok.Data; 10 | import org.bukkit.*; 11 | import org.bukkit.entity.Entity; 12 | import org.bukkit.entity.Player; 13 | import org.bukkit.inventory.Inventory; 14 | import org.bukkit.util.Vector; 15 | 16 | import java.util.ArrayList; 17 | 18 | @Data 19 | public class COIAirRaid extends COIBuilding { 20 | 21 | // 最小攻击伤害 22 | private double minDamage; 23 | // 最大攻击伤害 24 | private double maxDamage; 25 | // 每次攻击的之间的间隔时间(秒) 26 | private double coolDown; 27 | // 自动攻击 task 28 | private AirRaidTask turretCoolDown; 29 | 30 | // 攻击半径 31 | private double radius; 32 | 33 | // 弹药库 34 | private Inventory inventory; 35 | 36 | // 弹药消耗 37 | private int ammunitionConsumption; 38 | 39 | // 炮口位置 40 | private Location muzzle; 41 | 42 | public COIAirRaid() { 43 | // 最小伤害 44 | this.minDamage = 1d; 45 | // 最大伤害 46 | this.maxDamage = 3d; 47 | // 每次攻击的间隔时间 48 | this.coolDown = 3; 49 | // 攻击半径,如果发射方块和目标之间有其他方块挡着,是不会触发攻击的 50 | this.radius = 50; 51 | // 弹药库,如果里面有弹药,才能正常攻击,否则无法攻击 52 | // 每次攻击消耗 1 颗绿宝石 53 | // “大炮一响,黄金万两” 54 | this.inventory = GUIUtils.createAmmoInventory(6); 55 | // 每次攻击消耗的弹药 56 | this.ammunitionConsumption = 1; 57 | // 默认等级为1 58 | setLevel(1); 59 | // 初始化NPC创建器 60 | setNpcCreators(new ArrayList<>()); 61 | //初始化完成,可建造 62 | setAvailable(true); 63 | initStructure(); 64 | } 65 | 66 | 67 | @Override 68 | public BuildingConfig getDefaultConfig() { 69 | return new BuildingConfig() 70 | .setMaxLevel(10) 71 | .setMaxBuild(25) 72 | .setConsume(512) 73 | .setStructures(getBuildingLevelStructure()); 74 | } 75 | 76 | @Override 77 | public void buildSuccess(Location location, Player player) { 78 | super.buildSuccess(location, player); 79 | // 建造完成就开启自动检测周围敌方单位并攻击 80 | // 自动攻击Task 81 | this.turretCoolDown = new AirRaidTask(this); 82 | this.turretCoolDown.action(); 83 | 84 | } 85 | 86 | @Override 87 | public void upgradeBuildSuccess() { 88 | // 升级成功 89 | super.upgradeBuildSuccess(); 90 | // 先关闭 91 | Bukkit.getScheduler().cancelTask(this.getTurretCoolDown().getTaskId()); 92 | // 数据升级 93 | upgrade(); 94 | // 重启防御塔 95 | this.turretCoolDown = new AirRaidTask(this); 96 | this.turretCoolDown.action(); 97 | } 98 | 99 | @Override 100 | public void destroy(boolean effect) { 101 | super.destroy(effect); 102 | // 拆除成功后,关闭攻击task 103 | Bukkit.getScheduler().cancelTask(this.getTurretCoolDown().getTaskId()); 104 | } 105 | 106 | /** 107 | * 初始化设置矿场的建筑等级对照表 108 | */ 109 | private void initStructure() { 110 | getBuildingLevelStructure().put(1, "turret1.structure"); 111 | getBuildingLevelStructure().put(2, "turret2.structure"); 112 | getBuildingLevelStructure().put(3, "turret2.structure"); 113 | getBuildingLevelStructure().put(4, "turret2.structure"); 114 | getBuildingLevelStructure().put(5, "turret2.structure"); 115 | getBuildingLevelStructure().put(6, "turret2.structure"); 116 | getBuildingLevelStructure().put(7, "turret2.structure"); 117 | getBuildingLevelStructure().put(8, "turret2.structure"); 118 | getBuildingLevelStructure().put(9, "turret2.structure"); 119 | getBuildingLevelStructure().put(10, "turret2.structure"); 120 | } 121 | 122 | @Override 123 | public int getMaxHealth() { 124 | return 100 + getLevel() * 100; 125 | } 126 | 127 | 128 | 129 | /** 130 | * 升级 131 | */ 132 | private void upgrade(){ 133 | // 最小伤害 134 | this.minDamage = this.minDamage + 1; 135 | // 最大伤害 136 | this.maxDamage = this.maxDamage + 2; 137 | // 每次攻击的间隔时间 138 | if(this.coolDown > 1){ 139 | this.coolDown = this.coolDown - 1; 140 | } 141 | 142 | // 弹药消耗增大 143 | if(this.ammunitionConsumption < 5){ 144 | this.ammunitionConsumption = this.ammunitionConsumption + 1; 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/building/impl/COIBase.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.building.impl; 2 | 3 | import com.mcylm.coi.realm.tools.building.COIBuilding; 4 | import com.mcylm.coi.realm.tools.building.config.BuildingConfig; 5 | import org.bukkit.Location; 6 | import org.bukkit.entity.Player; 7 | 8 | import java.util.ArrayList; 9 | 10 | /** 11 | * 基地 12 | */ 13 | public class COIBase extends COIBuilding { 14 | 15 | public COIBase() { 16 | // 默认等级为1 17 | setLevel(1); 18 | // 初始化NPC创建器 19 | setNpcCreators(new ArrayList<>()); 20 | //初始化完成,可建造 21 | setAvailable(true); 22 | initStructure(); 23 | } 24 | 25 | @Override 26 | public BuildingConfig getDefaultConfig() { 27 | 28 | return new BuildingConfig() 29 | .setStructures(getBuildingLevelStructure()) 30 | .setMaxLevel(25) 31 | .setMaxBuild(1) 32 | .setShowInMenu(false) 33 | .setConsume(128); 34 | } 35 | 36 | @Override 37 | public void buildSuccess(Location location, Player player) { 38 | // 生成之后,把基地的箱子设置为资源共享箱子 39 | // 矿车会自动把物资运到这些箱子当中 40 | getTeam().setResourcesChests(getChestsLocation()); 41 | } 42 | 43 | @Override 44 | public void upgradeBuildSuccess() { 45 | super.upgradeBuildSuccess(); 46 | 47 | } 48 | 49 | @Override 50 | public void upgradeBuild(Player player) { 51 | super.upgradeBuild(player); 52 | } 53 | 54 | private void initStructure() { 55 | 56 | for(int i = 0;i<=100;i++){ 57 | getBuildingLevelStructure().put(i, "base1.structure"); 58 | } 59 | } 60 | 61 | @Override 62 | public int getMaxHealth() { 63 | return 500 + getLevel() * 500; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/building/impl/COIBridge.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.building.impl; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.tools.building.COIBuilding; 5 | import com.mcylm.coi.realm.tools.building.FloatableBuild; 6 | import com.mcylm.coi.realm.tools.building.config.BuildingConfig; 7 | import com.mcylm.coi.realm.utils.TeamUtils; 8 | import lombok.Data; 9 | import lombok.Getter; 10 | import lombok.Setter; 11 | import org.bukkit.Bukkit; 12 | import org.bukkit.Location; 13 | import org.bukkit.Material; 14 | import org.bukkit.block.Block; 15 | import org.bukkit.entity.Player; 16 | import org.bukkit.scheduler.BukkitRunnable; 17 | 18 | import java.util.HashSet; 19 | import java.util.Set; 20 | 21 | @Data 22 | public class COIBridge extends FloatableBuild { 23 | 24 | public COIBridge() { 25 | setLevel(1); 26 | setAvailable(true); 27 | initStructure(); 28 | } 29 | 30 | @Override 31 | public BuildingConfig getDefaultConfig() { 32 | return new BuildingConfig() 33 | .setConsume(64) 34 | .setMaxLevel(2) 35 | .setMaxBuild(9999) 36 | .setStructures(getBuildingLevelStructure()); 37 | } 38 | 39 | @Override 40 | public void buildSuccess(Location location, Player player) { 41 | super.buildSuccess(location, player); 42 | } 43 | 44 | @Override 45 | public int getMaxHealth() { 46 | return 200 + getLevel() * 50; 47 | } 48 | 49 | private void initStructure(){ 50 | getBuildingLevelStructure().put(1,"qiao1.structure"); 51 | getBuildingLevelStructure().put(2,"qiao1.structure"); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/building/impl/COIDoor.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.building.impl; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.tools.building.COIBuilding; 5 | import com.mcylm.coi.realm.tools.building.config.BuildingConfig; 6 | import com.mcylm.coi.realm.utils.TeamUtils; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | import org.bukkit.Bukkit; 10 | import org.bukkit.Location; 11 | import org.bukkit.Material; 12 | import org.bukkit.block.Block; 13 | import org.bukkit.entity.Player; 14 | import org.bukkit.scheduler.BukkitRunnable; 15 | 16 | import java.util.HashSet; 17 | import java.util.Set; 18 | 19 | @Setter 20 | @Getter 21 | public class COIDoor extends COIBuilding { 22 | 23 | private Set doorBlocks = new HashSet<>(); 24 | 25 | // 当前门是否是开着的 26 | private boolean open = false; 27 | private Material doorMaterial; 28 | 29 | public COIDoor() { 30 | setLevel(1); 31 | setDoorMaterial(Material.IRON_BLOCK); 32 | setAvailable(true); 33 | initStructure(); 34 | } 35 | 36 | @Override 37 | public BuildingConfig getDefaultConfig() { 38 | return new BuildingConfig() 39 | .setConsume(32) 40 | .setMaxLevel(2) 41 | .setMaxBuild(10) 42 | .setStructures(getBuildingLevelStructure()); 43 | } 44 | 45 | @Override 46 | public void buildSuccess(Location location, Player player) { 47 | super.buildSuccess(location, player); 48 | 49 | for (Block b : getBlocks()) { 50 | if (b.getType() == doorMaterial) { 51 | doorBlocks.add(b); 52 | } 53 | } 54 | 55 | // new BukkitRunnable() { 56 | // @Override 57 | // public void run() { 58 | // if (!isAlive()) { 59 | // this.cancel(); 60 | // return; 61 | // } 62 | // 63 | // boolean openDoor = false; 64 | // for (Player p : Entry.getInstance().getServer().getOnlinePlayers()) { 65 | // 66 | // if(!p.getWorld().getName().equals(Entry.WORLD)){ 67 | // TeamUtils.tpSpawner(p); 68 | // }else if(TeamUtils.inTeam(p.getName(),getTeam()) && p.getLocation().distance(location) <= 6) { 69 | // openDoor = true; 70 | // } 71 | // } 72 | // if (openDoor && !isOpen()) { 73 | // Bukkit.getScheduler().runTask(Entry.getInstance(), () -> open()); 74 | // } else if (!openDoor && isOpen()) { 75 | // Bukkit.getScheduler().runTask(Entry.getInstance(), () -> close()); 76 | // } 77 | // } 78 | // }.runTaskTimerAsynchronously(Entry.getInstance(), 1, 20); 79 | 80 | } 81 | 82 | /** 83 | * 自动开关门 84 | */ 85 | public void toggleDoor(){ 86 | if(this.open){ 87 | close(); 88 | }else open(); 89 | } 90 | 91 | @Override 92 | public int getMaxHealth() { 93 | return 300 + getLevel() * 200; 94 | } 95 | 96 | public void open() { 97 | if (!isAlive()) return; 98 | this.open = true; 99 | doorBlocks.forEach(b -> b.setType(Material.AIR)); 100 | } 101 | 102 | public void close() { 103 | if (!isAlive()) return; 104 | this.open = false; 105 | doorBlocks.forEach(b -> b.setType(doorMaterial)); 106 | } 107 | 108 | 109 | private void initStructure(){ 110 | getBuildingLevelStructure().put(1,"door1.structure"); 111 | getBuildingLevelStructure().put(2,"door2.structure"); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/building/impl/COIWall.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.building.impl; 2 | 3 | import com.mcylm.coi.realm.enums.COIBuildingType; 4 | import com.mcylm.coi.realm.tools.building.COIBuilding; 5 | import com.mcylm.coi.realm.tools.building.LineBuild; 6 | import com.mcylm.coi.realm.tools.building.config.BuildingConfig; 7 | import com.mcylm.coi.realm.tools.data.metadata.BuildData; 8 | import org.bukkit.block.Block; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | public class COIWall extends LineBuild { 12 | 13 | public COIWall() { 14 | initStructure(); 15 | setLevel(1); 16 | setAvailable(true); 17 | } 18 | 19 | @Override 20 | public BuildingConfig getDefaultConfig() { 21 | return new BuildingConfig() 22 | .setMaxLevel(3) 23 | .setMaxBuild(9999) 24 | .setConsume(8) 25 | .setStructures(getBuildingLevelStructure()); 26 | } 27 | 28 | @Override 29 | public LineBuild cloneBuild() { 30 | COIWall wall = new COIWall(); 31 | wall.setType(getType()); 32 | wall.setTeam(getTeam()); 33 | wall.setConfig(getConfig()); 34 | wall.setBuildPlayerName(getBuildPlayerName()); 35 | return wall; 36 | } 37 | 38 | @Override 39 | public boolean pointCheck(Block block) { 40 | @Nullable COIBuilding building = BuildData.getBuildingByBlock(block); 41 | 42 | if (building == null) { 43 | return true; 44 | } 45 | if (building.getType() == COIBuildingType.WALL_NORMAL) { 46 | return true; 47 | } 48 | return false; 49 | } 50 | 51 | private void initStructure(){ 52 | getBuildingLevelStructure().put(1,"wall1.structure"); 53 | getBuildingLevelStructure().put(2,"wall1.structure"); 54 | getBuildingLevelStructure().put(3,"wall1.structure"); 55 | 56 | } 57 | 58 | @Override 59 | public int getMaxHealth() { 60 | return 300 + getLevel() * 200; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/building/impl/COIWallOld.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.building.impl; 2 | 3 | import com.mcylm.coi.realm.enums.COIBuildingType; 4 | import com.mcylm.coi.realm.tools.building.COIBuilding; 5 | import com.mcylm.coi.realm.tools.building.ConnectableBuild; 6 | import com.mcylm.coi.realm.tools.building.config.BuildingConfig; 7 | import com.mcylm.coi.realm.tools.data.metadata.BuildData; 8 | import org.bukkit.Location; 9 | import org.bukkit.Material; 10 | import org.bukkit.block.Block; 11 | import org.bukkit.entity.Player; 12 | import org.bukkit.util.Vector; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | import java.util.List; 16 | 17 | @Deprecated 18 | public class COIWallOld extends ConnectableBuild { 19 | 20 | public COIWallOld() { 21 | setType(COIBuildingType.WALL_NORMAL); 22 | setLevel(1); 23 | setAvailable(true); 24 | } 25 | 26 | @Override 27 | public BuildingConfig getDefaultConfig() { 28 | return null; 29 | } 30 | 31 | @Override 32 | public void build(Location location, Player player) { 33 | super.build(location, player); 34 | for (int x = -1; x < 2; x++) { 35 | for (int z = -1; z < 2; z++) { 36 | buildWall(location.clone().add(x,0,z), -5, 8); 37 | } 38 | } 39 | buildSuccess(location, player); 40 | } 41 | 42 | @Override 43 | public void buildPoint(Location point, Vector line) { 44 | buildWall(point, -5, 6); 45 | } 46 | 47 | @Override 48 | public boolean connectConditionsCheck(ConnectableBuild to) { 49 | 50 | return (to.getType() == COIBuildingType.WALL_NORMAL || to.getType() == COIBuildingType.DOOR_NORMAL) && super.connectConditionsCheck(to); 51 | } 52 | 53 | @Override 54 | public boolean connectLineCheck(List line) { 55 | 56 | for (Location point : line) { 57 | @Nullable COIBuilding build = BuildData.getBuildingByBlock(point.getBlock()); 58 | 59 | if (build != null) { 60 | if (!(build.getType() == COIBuildingType.WALL_NORMAL || build.getType() == COIBuildingType.DOOR_NORMAL)) { 61 | return false; 62 | } 63 | } 64 | } 65 | return true; 66 | } 67 | 68 | @Override 69 | public int getMaxConnectBuild() { 70 | return 4; 71 | } 72 | 73 | public void buildWall(Location location, int minY, int maxY) { 74 | for (int y = minY; y < maxY; y++) { 75 | Block block = location.clone().add(0,y,0).getBlock(); 76 | if (!block.isSolid()) { 77 | COIBuilder.placeBlockForBuilding(block, this, Material.STONE); 78 | } 79 | } 80 | } 81 | 82 | @Override 83 | public int getMaxHealth() { 84 | return 200 + getLevel() * 100; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/building/impl/monster/COIMonsterBase.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.building.impl.monster; 2 | 3 | import com.mcylm.coi.realm.model.COINpc; 4 | import com.mcylm.coi.realm.tools.building.COIBuilding; 5 | import com.mcylm.coi.realm.tools.building.config.BuildingConfig; 6 | import com.mcylm.coi.realm.tools.npc.monster.COIPillagerCreator; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | import org.bukkit.Location; 10 | import org.bukkit.block.Block; 11 | import org.bukkit.entity.Entity; 12 | import org.bukkit.entity.Player; 13 | 14 | import java.util.List; 15 | 16 | public class COIMonsterBase extends COIBuilding { 17 | 18 | public COIMonsterBase() { 19 | setLevel(1); 20 | //初始化完成,可建造 21 | setAvailable(true); 22 | // 初始化NPC创建器 23 | setNpcCreators(List.of( 24 | // 一个野怪小队1个人 25 | COIPillagerCreator.initCOIPillagerCreator(null) 26 | )); 27 | initStructure(); 28 | } 29 | 30 | @Setter 31 | @Getter 32 | private boolean canBeDamaged; 33 | @Override 34 | public BuildingConfig getDefaultConfig() { 35 | return new BuildingConfig() 36 | .setMaxLevel(3) 37 | .setConsume(-1) 38 | .setShowInMenu(false) 39 | .setStructures(getBuildingLevelStructure()); 40 | } 41 | 42 | @Override 43 | public void damage(Entity attacker, int damage, Block attackBlock) { 44 | if (canBeDamaged) { 45 | super.damage(attacker, damage, attackBlock); 46 | } 47 | } 48 | 49 | @Override 50 | public void buildSuccess(Location location, Player player) { 51 | 52 | if (isComplete()) { 53 | for (COINpc creator : getNpcCreators()) { 54 | COIPillagerCreator npcCreator = (COIPillagerCreator) creator; 55 | 56 | npcCreator.createMonster(this); 57 | } 58 | } 59 | } 60 | 61 | @Override 62 | public int getMaxHealth() { 63 | return 500; 64 | } 65 | 66 | private void initStructure(){ 67 | getBuildingLevelStructure().put(1,"monster1.structure"); 68 | getBuildingLevelStructure().put(2,"monster1.structure"); 69 | getBuildingLevelStructure().put(3,"monster1.structure"); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/data/MapData.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.data; 2 | 3 | import com.mcylm.coi.realm.tools.map.COIMobSpawnPoint; 4 | import com.mcylm.coi.realm.tools.map.COIVein; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * 游戏地图数据 14 | */ 15 | 16 | @Setter 17 | @Getter 18 | @NoArgsConstructor 19 | public class MapData { 20 | 21 | // 矿脉的位置 22 | private List veins = new ArrayList<>(); 23 | 24 | // 野怪的位置 25 | private List mobSpawnPoints = new ArrayList<>(); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/data/SkinData.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.data; 2 | 3 | import com.mcylm.coi.realm.enums.COIBuildingType; 4 | import com.mcylm.coi.realm.model.COISkin; 5 | import com.mcylm.coi.realm.tools.map.COIVein; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Data; 8 | import lombok.Getter; 9 | import lombok.NoArgsConstructor; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | /** 16 | * 玩家的建筑/NPC 皮肤类 17 | */ 18 | 19 | @Data 20 | @NoArgsConstructor 21 | public class SkinData { 22 | 23 | // 建筑皮肤类 24 | private List skins = new ArrayList<>(); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/data/metadata/AttackTeamData.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.data.metadata; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.model.COINpc; 5 | import com.mcylm.coi.realm.tools.attack.team.AttackTeam; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | import org.bukkit.entity.Entity; 9 | import org.bukkit.metadata.MetadataValue; 10 | import org.bukkit.plugin.Plugin; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Nullable; 13 | 14 | @Getter 15 | @Setter 16 | public class AttackTeamData implements MetadataValue { 17 | 18 | 19 | private AttackTeam currentTeam; 20 | 21 | private Status status = Status.FOLLOWING; 22 | 23 | public AttackTeamData(AttackTeam attackTeam) { 24 | this.currentTeam = attackTeam; 25 | } 26 | 27 | @Nullable 28 | public static AttackTeamData getDataByEntity(Entity entity) { 29 | for (MetadataValue value : entity.getMetadata("teamData")) { 30 | if (value.asString().equals("TEAM_DATA")) { 31 | return (AttackTeamData) value; 32 | } 33 | } 34 | return null; 35 | } 36 | 37 | private COINpc npc; 38 | 39 | @Override 40 | public @Nullable Object value() { 41 | return null; 42 | } 43 | 44 | @Override 45 | public int asInt() { 46 | return 0; 47 | } 48 | 49 | @Override 50 | public float asFloat() { 51 | return 0; 52 | } 53 | 54 | @Override 55 | public double asDouble() { 56 | return 0; 57 | } 58 | 59 | @Override 60 | public long asLong() { 61 | return 0; 62 | } 63 | 64 | @Override 65 | public short asShort() { 66 | return 0; 67 | } 68 | 69 | @Override 70 | public byte asByte() { 71 | return 0; 72 | } 73 | 74 | @Override 75 | public boolean asBoolean() { 76 | return false; 77 | } 78 | 79 | @Override 80 | public @NotNull String asString() { 81 | return "TEAM_DATA"; 82 | } 83 | 84 | @Override 85 | public @Nullable Plugin getOwningPlugin() { 86 | return Entry.getInstance(); 87 | } 88 | 89 | @Override 90 | public void invalidate() { 91 | 92 | } 93 | 94 | public enum Status { 95 | FOLLOWING, 96 | OTHER 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/data/metadata/BuildData.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.data.metadata; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.tools.building.COIBuilding; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import org.bukkit.block.Block; 8 | import org.bukkit.metadata.MetadataValue; 9 | import org.bukkit.plugin.Plugin; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | @Data 14 | @AllArgsConstructor 15 | public class BuildData implements MetadataValue { 16 | 17 | @Nullable 18 | public static COIBuilding getBuildingByBlock(Block block) { 19 | 20 | try{ 21 | for (MetadataValue value : block.getMetadata("building")) { 22 | if (value.asString().equals("BUILDING_DATA")) { 23 | return ((BuildData) value).getBuilding(); 24 | } 25 | } 26 | }catch (Exception e){ 27 | // 如果BUILDING_DATA丢了,就返回null 28 | return null; 29 | } 30 | 31 | 32 | return null; 33 | } 34 | 35 | private COIBuilding building; 36 | 37 | @Override 38 | public @Nullable Object value() { 39 | return null; 40 | } 41 | 42 | @Override 43 | public int asInt() { 44 | return 0; 45 | } 46 | 47 | @Override 48 | public float asFloat() { 49 | return 0; 50 | } 51 | 52 | @Override 53 | public double asDouble() { 54 | return 0; 55 | } 56 | 57 | @Override 58 | public long asLong() { 59 | return 0; 60 | } 61 | 62 | @Override 63 | public short asShort() { 64 | return 0; 65 | } 66 | 67 | @Override 68 | public byte asByte() { 69 | return 0; 70 | } 71 | 72 | @Override 73 | public boolean asBoolean() { 74 | return false; 75 | } 76 | 77 | @Override 78 | public @NotNull String asString() { 79 | return "BUILDING_DATA"; 80 | } 81 | 82 | @Override 83 | public @Nullable Plugin getOwningPlugin() { 84 | return Entry.getInstance(); 85 | } 86 | 87 | @Override 88 | public void invalidate() { 89 | 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/data/metadata/EntityData.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.data.metadata; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.model.COINpc; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Getter; 7 | import org.bukkit.entity.Entity; 8 | import org.bukkit.metadata.MetadataValue; 9 | import org.bukkit.plugin.Plugin; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | @Getter 14 | @AllArgsConstructor 15 | public class EntityData implements MetadataValue { 16 | 17 | @Nullable 18 | public static COINpc getNpcByEntity(Entity entity) { 19 | for (MetadataValue value : entity.getMetadata("entityData")) { 20 | if (value.asString().equals("ENTITY_DATA")) { 21 | return ((EntityData) value).getNpc(); 22 | } 23 | } 24 | return null; 25 | } 26 | 27 | private COINpc npc; 28 | 29 | @Override 30 | public @Nullable Object value() { 31 | return null; 32 | } 33 | 34 | @Override 35 | public int asInt() { 36 | return 0; 37 | } 38 | 39 | @Override 40 | public float asFloat() { 41 | return 0; 42 | } 43 | 44 | @Override 45 | public double asDouble() { 46 | return 0; 47 | } 48 | 49 | @Override 50 | public long asLong() { 51 | return 0; 52 | } 53 | 54 | @Override 55 | public short asShort() { 56 | return 0; 57 | } 58 | 59 | @Override 60 | public byte asByte() { 61 | return 0; 62 | } 63 | 64 | @Override 65 | public boolean asBoolean() { 66 | return false; 67 | } 68 | 69 | @Override 70 | public @NotNull String asString() { 71 | return "ENTITY_DATA"; 72 | } 73 | 74 | @Override 75 | public @Nullable Plugin getOwningPlugin() { 76 | return Entry.getInstance(); 77 | } 78 | 79 | @Override 80 | public void invalidate() { 81 | 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/data/metadata/MonsterData.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.data.metadata; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.model.COINpc; 5 | import com.mcylm.coi.realm.tools.attack.target.Target; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | import org.bukkit.entity.Entity; 9 | import org.bukkit.metadata.MetadataValue; 10 | import org.bukkit.plugin.Plugin; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Nullable; 13 | 14 | 15 | @Getter 16 | @Setter 17 | public class MonsterData implements MetadataValue { 18 | 19 | private Target target; 20 | 21 | 22 | @Nullable 23 | public static MonsterData getDataByEntity(Entity entity) { 24 | for (MetadataValue value : entity.getMetadata("monsterData")) { 25 | if (value.asString().equals("MONSTER_DATA")) { 26 | return (MonsterData) value; 27 | } 28 | } 29 | return null; 30 | } 31 | 32 | private COINpc npc; 33 | 34 | @Override 35 | public @Nullable Object value() { 36 | return null; 37 | } 38 | 39 | @Override 40 | public int asInt() { 41 | return 0; 42 | } 43 | 44 | @Override 45 | public float asFloat() { 46 | return 0; 47 | } 48 | 49 | @Override 50 | public double asDouble() { 51 | return 0; 52 | } 53 | 54 | @Override 55 | public long asLong() { 56 | return 0; 57 | } 58 | 59 | @Override 60 | public short asShort() { 61 | return 0; 62 | } 63 | 64 | @Override 65 | public byte asByte() { 66 | return 0; 67 | } 68 | 69 | @Override 70 | public boolean asBoolean() { 71 | return false; 72 | } 73 | 74 | @Override 75 | public @NotNull String asString() { 76 | return "MONSTER_DATA"; 77 | } 78 | 79 | @Override 80 | public @Nullable Plugin getOwningPlugin() { 81 | return Entry.getInstance(); 82 | } 83 | 84 | @Override 85 | public void invalidate() { 86 | 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/goals/citizens/NPCLookForTargetGoal.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.goals.citizens; 2 | 3 | import com.mcylm.coi.realm.tools.attack.DamageableAI; 4 | import net.citizensnpcs.api.ai.tree.BehaviorGoalAdapter; 5 | import net.citizensnpcs.api.ai.tree.BehaviorStatus; 6 | import org.bukkit.entity.Mob; 7 | 8 | public class NPCLookForTargetGoal extends BehaviorGoalAdapter { 9 | private Mob entity; 10 | 11 | private DamageableAI ai; 12 | 13 | private int tick = 0; 14 | public NPCLookForTargetGoal(DamageableAI ai) { 15 | this.ai = ai; 16 | this.entity = (Mob) ai.asEntity().getNpc().getEntity(); 17 | 18 | } 19 | /* 20 | @Override 21 | public boolean shouldActivate() { 22 | 23 | } 24 | 25 | @Override 26 | public void tick() { 27 | 28 | } 29 | 30 | @Override 31 | public void start() { 32 | LoggerUtils.debug("start find"); 33 | } 34 | 35 | @Override 36 | public void stop() { 37 | LoggerUtils.debug("stop find"); 38 | } 39 | @Override 40 | public @NotNull GoalKey getKey() { 41 | return GoalKey.of(Mob.class, Entry.getNamespacedKey("npc_look_for_target")); 42 | } 43 | 44 | @Override 45 | public @NotNull EnumSet getTypes() { 46 | return EnumSet.of(GoalType.TARGET); 47 | } 48 | 49 | 50 | */ 51 | 52 | @Override 53 | public void reset() { 54 | 55 | } 56 | 57 | @Override 58 | public BehaviorStatus run() { 59 | if (tick++ > 4) { 60 | tick = 0; 61 | ai.lookForEnemy(-1); 62 | } 63 | return BehaviorStatus.RUNNING; 64 | 65 | 66 | } 67 | 68 | @Override 69 | public boolean shouldExecute() { 70 | if (!ai.asEntity().isAlive()) { 71 | return false; 72 | } 73 | this.entity = (Mob)ai.asEntity().getNpc().getEntity(); 74 | 75 | if (ai.asEntity().isTooHungryToWork()) { 76 | return false; 77 | } 78 | 79 | if (ai.getTarget() == null) { 80 | return true; 81 | } 82 | return false; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/goals/citizens/NPCMoveAroundBehavior.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.goals.citizens; 2 | 3 | public class NPCMoveAroundBehavior { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/goals/citizens/NPCMoveToTargetPointGoal.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.goals.citizens; 2 | 3 | import com.mcylm.coi.realm.tools.attack.team.AttackTeam; 4 | import com.mcylm.coi.realm.tools.data.metadata.AttackTeamData; 5 | import com.mcylm.coi.realm.tools.npc.impl.COIEntity; 6 | import com.mcylm.coi.realm.tools.npc.impl.COISoldier; 7 | import net.citizensnpcs.api.ai.tree.BehaviorGoalAdapter; 8 | import net.citizensnpcs.api.ai.tree.BehaviorStatus; 9 | import org.bukkit.Location; 10 | import org.bukkit.entity.Mob; 11 | 12 | public class NPCMoveToTargetPointGoal extends BehaviorGoalAdapter { 13 | 14 | private Mob entity; 15 | 16 | private COIEntity coiEntity; 17 | 18 | private AttackTeam team; 19 | 20 | private Location currentTarget; 21 | 22 | boolean reach = true; 23 | 24 | public NPCMoveToTargetPointGoal(COIEntity entity) { 25 | this.coiEntity = entity; 26 | this.entity = (Mob) entity.getNpc().getEntity(); 27 | 28 | } 29 | 30 | @Override 31 | public void reset() { 32 | 33 | } 34 | 35 | @Override 36 | public BehaviorStatus run() { 37 | 38 | if (currentTarget != team.getTarget()) { 39 | currentTarget = team.getTarget(); 40 | reach = false; 41 | } 42 | 43 | if (!reach) { 44 | if (coiEntity instanceof COISoldier soldier) { 45 | soldier.setTarget(null); 46 | entity.setTarget(null); 47 | } 48 | coiEntity.findPath(currentTarget); 49 | } 50 | 51 | if (entity.getLocation().distance(currentTarget) < 3.5) { 52 | reach = true; 53 | } 54 | 55 | return BehaviorStatus.RUNNING; 56 | 57 | } 58 | 59 | @Override 60 | public boolean shouldExecute() { 61 | if (!coiEntity.isAlive()) { 62 | return false; 63 | } 64 | this.entity = (Mob) coiEntity.getNpc().getEntity(); 65 | 66 | 67 | AttackTeamData teamData = AttackTeamData.getDataByEntity(entity); 68 | 69 | if (teamData == null) { 70 | return false; 71 | } 72 | 73 | team = teamData.getCurrentTeam(); 74 | 75 | if (team.getCommander().isDead()) { 76 | return false; 77 | } 78 | 79 | if (coiEntity.isTooHungryToWork()) { 80 | return false; 81 | } 82 | 83 | if (reach && currentTarget != null && currentTarget == team.getTarget()) { 84 | return false; 85 | } 86 | 87 | return true; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/goals/citizens/NPCSimpleMeleeAttackGoal.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.goals.citizens; 2 | 3 | import com.mcylm.coi.realm.tools.attack.DamageableAI; 4 | import com.mcylm.coi.realm.tools.attack.target.Target; 5 | import com.mcylm.coi.realm.tools.attack.target.TargetType; 6 | import com.mcylm.coi.realm.tools.attack.target.impl.EntityTarget; 7 | import com.mcylm.coi.realm.tools.building.COIBuilding; 8 | import com.mcylm.coi.realm.tools.data.metadata.BuildData; 9 | import com.mcylm.coi.realm.utils.DamageUtils; 10 | import com.mcylm.coi.realm.utils.LocationUtils; 11 | import net.citizensnpcs.api.ai.tree.BehaviorGoalAdapter; 12 | import net.citizensnpcs.api.ai.tree.BehaviorStatus; 13 | import org.bukkit.Effect; 14 | import org.bukkit.Material; 15 | import org.bukkit.block.Block; 16 | import org.bukkit.entity.Mob; 17 | 18 | public class NPCSimpleMeleeAttackGoal extends BehaviorGoalAdapter { 19 | 20 | 21 | private Mob entity; 22 | 23 | private DamageableAI ai; 24 | 25 | private int attackCooldown = 0; 26 | 27 | 28 | public NPCSimpleMeleeAttackGoal(DamageableAI ai) { 29 | this.ai = ai; 30 | this.entity = (Mob) ai.asEntity().getNpc().getEntity(); 31 | 32 | } 33 | @Override 34 | public void reset() { 35 | 36 | } 37 | 38 | @Override 39 | public BehaviorStatus run() { 40 | 41 | 42 | if (attackCooldown > 0) { 43 | attackCooldown--; 44 | return BehaviorStatus.RUNNING; 45 | } 46 | 47 | // 在攻击伤害范围内,随机产生伤害 48 | double damage = DamageUtils.getRandomDamage(ai.asEntity().getCoiNpc()); 49 | 50 | // 攻击建筑 51 | for (Block b : LocationUtils.selectionRadiusByDistance(entity.getLocation().getBlock(), 3, 3)) { 52 | COIBuilding building = BuildData.getBuildingByBlock(b); 53 | if (building != null && building.getTeam() != ai.asEntity().getCoiNpc().getTeam()) { 54 | entity.swingMainHand(); 55 | building.damage(entity, (int) damage, b); 56 | attackCooldown = 25; 57 | b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, 1); 58 | break; 59 | } 60 | } 61 | 62 | Mob npcEntity = entity; 63 | 64 | Target target = ai.getTarget(); 65 | 66 | if (target.getType() == TargetType.BUILDING) { 67 | // TODO 弓箭射击建筑 (创造个临时实体作为目标) 68 | ai.findPath(target.getTargetLocation()); 69 | 70 | } 71 | if (target.getType() == TargetType.ENTITY && npcEntity.getEquipment().getItemInMainHand().getType() == Material.CROSSBOW) { 72 | npcEntity.setTarget(((EntityTarget) target).getEntity()); 73 | } else { 74 | if (ai.asEntity().getNpc().getEntity().getLocation().distance(target.getTargetLocation()) <= 3 && target.getType() == TargetType.ENTITY) { 75 | // 挥动手 76 | entity.swingMainHand(); 77 | attackCooldown = 10; 78 | ai.damage(target, damage, target.getTargetLocation()); 79 | 80 | entity.lookAt(target.getTargetLocation()); 81 | 82 | } 83 | ai.findPath(target.getTargetLocation()); 84 | 85 | } 86 | return BehaviorStatus.RUNNING; 87 | } 88 | 89 | @Override 90 | public boolean shouldExecute() { 91 | 92 | if (!ai.asEntity().isAlive()) { 93 | return false; 94 | } 95 | this.entity = (Mob)ai.asEntity().getNpc().getEntity(); 96 | 97 | 98 | if (ai.asEntity().isTooHungryToWork()) { 99 | return false; 100 | } 101 | 102 | 103 | 104 | if (entity.getEquipment().getItemInMainHand().getType() == Material.CROSSBOW) { 105 | if (ai.getTarget() != null && ai.getTarget().getType() != TargetType.BUILDING) { 106 | return false; 107 | } 108 | } 109 | 110 | if (ai.getTarget() != null && !ai.getTarget().isDead()) { 111 | return true; 112 | } 113 | 114 | return false; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/goals/paper/MonsterAttackBuildingGoal.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.goals.paper; 2 | 3 | import com.destroystokyo.paper.entity.ai.Goal; 4 | import com.destroystokyo.paper.entity.ai.GoalKey; 5 | import com.destroystokyo.paper.entity.ai.GoalType; 6 | import com.mcylm.coi.realm.Entry; 7 | import com.mcylm.coi.realm.tools.building.COIBuilding; 8 | import com.mcylm.coi.realm.tools.data.metadata.BuildData; 9 | import com.mcylm.coi.realm.utils.LocationUtils; 10 | import com.mcylm.coi.realm.utils.TeamUtils; 11 | import org.bukkit.Effect; 12 | import org.bukkit.block.Block; 13 | import org.bukkit.entity.Monster; 14 | import org.jetbrains.annotations.NotNull; 15 | 16 | import java.util.EnumSet; 17 | 18 | public class MonsterAttackBuildingGoal implements Goal { 19 | 20 | private Monster entity; 21 | 22 | int damage; 23 | 24 | int attackCooldown = 0; 25 | 26 | int tick = 0; 27 | public MonsterAttackBuildingGoal(Monster entity, int damage) { 28 | this.entity = entity; 29 | this.damage = damage; 30 | } 31 | 32 | @Override 33 | public boolean shouldActivate() { 34 | return !entity.isDead(); 35 | } 36 | 37 | @Override 38 | public void tick() { 39 | 40 | if (attackCooldown-- < 0) { 41 | attackCooldown = 20; 42 | for (Block b : LocationUtils.selectionRadiusByDistance(entity.getLocation().getBlock(), 3, 3)) { 43 | COIBuilding building = BuildData.getBuildingByBlock(b); 44 | if (building != null && building.getTeam() != TeamUtils.getMonsterTeam()) { 45 | entity.swingMainHand(); 46 | building.damage(entity, damage, b); 47 | b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, 1); 48 | break; 49 | } 50 | } 51 | } 52 | } 53 | 54 | @Override 55 | public @NotNull GoalKey getKey() { 56 | return GoalKey.of(Monster.class, Entry.getNamespacedKey("attack_building")); 57 | } 58 | 59 | @Override 60 | public @NotNull EnumSet getTypes() { 61 | return EnumSet.of(GoalType.UNKNOWN_BEHAVIOR); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/goals/paper/MonsterLookForBuildingTargetGoal.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.goals.paper; 2 | 3 | import com.destroystokyo.paper.entity.ai.Goal; 4 | import com.destroystokyo.paper.entity.ai.GoalKey; 5 | import com.destroystokyo.paper.entity.ai.GoalType; 6 | import com.mcylm.coi.realm.Entry; 7 | import com.mcylm.coi.realm.enums.COIBuildingType; 8 | import com.mcylm.coi.realm.enums.COITeamType; 9 | import com.mcylm.coi.realm.tools.attack.target.impl.BuildingTarget; 10 | import com.mcylm.coi.realm.tools.building.COIBuilding; 11 | import com.mcylm.coi.realm.tools.data.metadata.MonsterData; 12 | import com.mcylm.coi.realm.utils.LocationUtils; 13 | import lombok.AllArgsConstructor; 14 | import org.bukkit.Bukkit; 15 | import org.bukkit.entity.Monster; 16 | import org.bukkit.scheduler.BukkitRunnable; 17 | import org.jetbrains.annotations.NotNull; 18 | 19 | import java.util.EnumSet; 20 | import java.util.concurrent.CompletableFuture; 21 | 22 | @AllArgsConstructor 23 | public class MonsterLookForBuildingTargetGoal implements Goal { 24 | 25 | private Monster monster; 26 | 27 | private int tick = 0; 28 | 29 | private CompletableFuture targetFuture = null; 30 | 31 | 32 | public MonsterLookForBuildingTargetGoal(Monster monster) { 33 | this.monster = monster; 34 | // 为了不干扰原版 使用BukkitRunnable 35 | MonsterLookForBuildingTargetGoal goal = this; 36 | new BukkitRunnable() { 37 | @Override 38 | public void run() { 39 | 40 | if (monster.isDead() || Bukkit.isStopping()) { 41 | this.cancel(); 42 | return; 43 | } 44 | 45 | 46 | MonsterData data = MonsterData.getDataByEntity(monster); 47 | 48 | if (monster.getTarget() == null || monster.getTarget().isDead()) { 49 | if (data.getTarget() != null && !data.getTarget().isDead()) { 50 | Entry.runSync(() -> { 51 | if (monster.getPathfinder().getCurrentPath() != null && monster.getPathfinder().getCurrentPath().getFinalPoint().distance(data.getTarget().getTargetLocation()) < 2) { 52 | return; 53 | } 54 | monster.getPathfinder().moveTo(data.getTarget().getTargetLocation()); 55 | }); 56 | } 57 | } 58 | 59 | if (data.getTarget() != null && data.getTarget().isDead()) { 60 | data.setTarget(null); 61 | } 62 | 63 | if (goal.shouldActivate()) { 64 | goal.tick(); 65 | } 66 | } 67 | }.runTaskTimerAsynchronously(Entry.getInstance(), 1,10); 68 | 69 | } 70 | 71 | @Override 72 | public boolean shouldActivate() { 73 | 74 | if (monster.getTarget() != null && !monster.getTarget().isDead()) { 75 | if (monster.getTarget().getLocation().distance(monster.getLocation()) < 10) { 76 | return false; 77 | } 78 | } 79 | MonsterData data = MonsterData.getDataByEntity(monster); 80 | if (data != null && data.getTarget() != null && !data.getTarget().isDead()) { 81 | return false; 82 | } 83 | 84 | return true; 85 | } 86 | 87 | @Override 88 | public void tick() { 89 | 90 | monster.setTarget(null); 91 | MonsterData data = MonsterData.getDataByEntity(monster); 92 | 93 | for (COIBuilding building : LocationUtils.selectionBuildingsByDistance(monster.getLocation(), 200, EnumSet.of(COITeamType.MONSTER), true)) { 94 | if (building.getType() != COIBuildingType.WALL_NORMAL) { 95 | data.setTarget(new BuildingTarget(building, building.getNearestBlock(monster.getLocation()).getLocation(), 6)); 96 | } 97 | } 98 | 99 | 100 | 101 | } 102 | 103 | 104 | @Override 105 | public @NotNull GoalKey getKey() { 106 | return GoalKey.of(Monster.class, Entry.getNamespacedKey("look_for_target")); 107 | } 108 | 109 | @Override 110 | public @NotNull EnumSet getTypes() { 111 | return EnumSet.of(GoalType.UNKNOWN_BEHAVIOR); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/handler/BlockPlaceCondition.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.handler; 2 | 3 | import com.mcylm.coi.realm.model.COIBlock; 4 | import org.bukkit.Material; 5 | import org.bukkit.block.Block; 6 | 7 | public interface BlockPlaceCondition { 8 | boolean check(Block block, COIBlock blockToPlace, Material material); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/handler/BlockPlaceHandler.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.handler; 2 | 3 | import com.mcylm.coi.realm.model.COIBlock; 4 | import org.bukkit.Material; 5 | import org.bukkit.block.Block; 6 | 7 | public interface BlockPlaceHandler { 8 | 9 | Material handle(Block block, COIBlock blockToPlace, Material material); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/handler/SpawnHandler.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.handler; 2 | 3 | import org.bukkit.Location; 4 | 5 | public interface SpawnHandler { 6 | 7 | void spawn(int second, Location location); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/map/COIMobSpawnPoint.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.map; 2 | 3 | import com.google.gson.annotations.Expose; 4 | import com.mcylm.coi.realm.tools.handler.SpawnHandler; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | import org.bukkit.Bukkit; 9 | import org.bukkit.Location; 10 | 11 | import java.util.List; 12 | import java.util.Random; 13 | 14 | @Setter 15 | @Getter 16 | @NoArgsConstructor 17 | public class COIMobSpawnPoint { 18 | 19 | public static Random random = new Random(); 20 | 21 | private int x; 22 | private int y; 23 | private int z; 24 | private String world; 25 | private int maxRadius; 26 | 27 | @Expose(deserialize = false, serialize = false) 28 | public List handlers; 29 | 30 | public COIMobSpawnPoint(int x, int y, int z, String world, int maxRadius) { 31 | this.x = x; 32 | this.y = y; 33 | this.z = z; 34 | this.world = world; 35 | this.maxRadius = maxRadius; 36 | } 37 | 38 | public Location getLocation() { 39 | return new Location(Bukkit.getWorld(world), x, y, z); 40 | } 41 | 42 | public void spawn(int second) { 43 | 44 | Location location = getLocation(); 45 | 46 | for (SpawnHandler handler : handlers) { 47 | handler.spawn(second, location.getWorld().getHighestBlockAt(location.getBlockX() + random.nextInt(-maxRadius, maxRadius), location.getBlockZ() + random.nextInt(-maxRadius, maxRadius)).getLocation()); 48 | } 49 | 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/map/COIVein.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.map; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.model.COIPaster; 5 | import com.mcylm.coi.realm.model.COIStructure; 6 | import com.mcylm.coi.realm.utils.rotation.Rotation; 7 | import lombok.AllArgsConstructor; 8 | import lombok.Getter; 9 | import lombok.NoArgsConstructor; 10 | import org.bukkit.Bukkit; 11 | import org.bukkit.Location; 12 | import org.bukkit.Material; 13 | import org.bukkit.scheduler.BukkitRunnable; 14 | import org.jetbrains.annotations.NotNull; 15 | 16 | import java.util.List; 17 | 18 | @NoArgsConstructor 19 | @AllArgsConstructor 20 | public class COIVein { 21 | 22 | private String structureName; 23 | private int x; 24 | private int y; 25 | private int z; 26 | private float yaw; 27 | 28 | private String world; 29 | @Getter 30 | private double spawnChance; 31 | 32 | private int resetTime; 33 | 34 | public BukkitRunnable startGenerate() { 35 | 36 | Location location = getLocation(); 37 | @NotNull BukkitRunnable runnable = new BukkitRunnable() { 38 | @Override 39 | public void run() { 40 | 41 | placeVein(location); 42 | 43 | } 44 | }; 45 | runnable.runTaskTimer(Entry.getInstance(), 0, resetTime * 20L); 46 | return runnable; 47 | } 48 | 49 | public Location getLocation() { 50 | return new Location(Bukkit.getWorld(world), x, y, z); 51 | } 52 | 53 | public void placeVein(Location location) { 54 | COIStructure structure = Entry.getBuilder().getStructureByFile(structureName); 55 | structure.rotate(Rotation.fromDegrees(Math.round(yaw / 90) * 90)); 56 | Entry.getBuilder().pasteStructureWithoutBuilding(new COIPaster(false, 5, 5, world, location, null , structure, false, Material.STONE, List.of(), ((block, blockToPlace, material) -> material)), null); 57 | } 58 | 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/monster/custom/CustomMonster.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.monster.custom; 2 | 3 | import org.bukkit.entity.EntityType; 4 | import org.bukkit.entity.Monster; 5 | 6 | public interface CustomMonster { 7 | void spawn(Monster monster); 8 | 9 | EntityType getType(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/monster/custom/impl/GiantMonster.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.monster.custom.impl; 2 | 3 | import com.mcylm.coi.realm.tools.monster.custom.CustomMonster; 4 | import me.libraryaddict.disguise.DisguiseAPI; 5 | import me.libraryaddict.disguise.LibsDisguises; 6 | import me.libraryaddict.disguise.disguisetypes.Disguise; 7 | import me.libraryaddict.disguise.disguisetypes.DisguiseType; 8 | import me.libraryaddict.disguise.disguisetypes.MobDisguise; 9 | import org.bukkit.attribute.Attribute; 10 | import org.bukkit.attribute.AttributeModifier; 11 | import org.bukkit.entity.EntityType; 12 | import org.bukkit.entity.Monster; 13 | 14 | import java.util.UUID; 15 | 16 | public class GiantMonster implements CustomMonster { 17 | @Override 18 | public void spawn(Monster monster) { 19 | DisguiseAPI.disguiseEntity(monster, new MobDisguise(DisguiseType.GIANT)); 20 | monster.getAttribute(Attribute.GENERIC_MAX_HEALTH) 21 | .addModifier(new AttributeModifier("health", 100, AttributeModifier.Operation.ADD_NUMBER)); 22 | monster.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED) 23 | .addModifier(new AttributeModifier("speed", 0.7, AttributeModifier.Operation.ADD_SCALAR)); 24 | 25 | } 26 | 27 | @Override 28 | public EntityType getType() { 29 | return EntityType.RAVAGER; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/monster/custom/impl/VanillaMonster.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.monster.custom.impl; 2 | 3 | import com.mcylm.coi.realm.tools.monster.custom.CustomMonster; 4 | import lombok.AllArgsConstructor; 5 | import org.bukkit.entity.EntityType; 6 | import org.bukkit.entity.Monster; 7 | 8 | @AllArgsConstructor 9 | public class VanillaMonster implements CustomMonster { 10 | private EntityType type; 11 | 12 | @Override 13 | public void spawn(Monster monster) { 14 | 15 | } 16 | 17 | @Override 18 | public EntityType getType() { 19 | return type; 20 | } 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/npc/AI.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.npc; 2 | 3 | import com.mcylm.coi.realm.model.COINpc; 4 | import com.mcylm.coi.realm.tools.npc.impl.COIEntity; 5 | import org.bukkit.Location; 6 | import org.bukkit.block.Block; 7 | import org.bukkit.entity.Entity; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * AI的接口层,AI的基础能力 13 | */ 14 | public interface AI { 15 | 16 | // 创建NPC 17 | COIEntity create(COINpc coiNpc); 18 | 19 | // 更新NPC 20 | COIEntity update(COINpc coiNpc, boolean respawn); 21 | 22 | // AI寻路 23 | void findPath(Location location); 24 | 25 | // 说话 26 | void say(String message); 27 | 28 | // 捡起地上的东西 29 | void pickItems(); 30 | 31 | // 吃东西 32 | void eatFood(); 33 | 34 | // 自动穿衣服 35 | void wearClothes(); 36 | 37 | // 获取NPC附近的方块 38 | List getNearbyBlocks(double radius); 39 | 40 | // 获取NPC附近的生物 41 | List getNearByEntities(double radius); 42 | 43 | // 移动 44 | void move(); 45 | 46 | // 生成NPC 47 | void spawn(Location location); 48 | 49 | // 消除NPC 50 | void despawn(); 51 | 52 | // 彻底清除NPC 53 | void remove(); 54 | 55 | // 是否还或者 56 | boolean isAlive(); 57 | 58 | // 是否被清除 59 | boolean isRemoved(); 60 | 61 | // 获取NPC位置 62 | Location getLocation(); 63 | 64 | 65 | default int delayTick() { 66 | return 20; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/npc/COICartCreator.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.npc; 2 | 3 | import com.mcylm.coi.realm.model.COINpc; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import org.bukkit.Location; 7 | 8 | import java.util.List; 9 | 10 | @EqualsAndHashCode(callSuper = true) 11 | @Data 12 | public class COICartCreator extends COINpc { 13 | 14 | // 搬运工 15 | public COICartCreator(List chestsLocation) { 16 | super(); 17 | this.chestsLocation = chestsLocation; 18 | } 19 | 20 | // 收集够这些资源就回去,默认5个 21 | private Integer resourceLimitToBack = 5; 22 | 23 | // 存放资源的箱子 24 | private List toSaveResourcesLocations; 25 | 26 | // 收集的物资存放箱子的位置,可以有多个 27 | private List chestsLocation; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/npc/COIFarmerCreator.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.npc; 2 | 3 | import com.mcylm.coi.realm.model.COINpc; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import org.bukkit.Location; 7 | 8 | import java.util.List; 9 | 10 | @EqualsAndHashCode(callSuper = true) 11 | @Data 12 | public class COIFarmerCreator extends COINpc { 13 | 14 | // 必须要有装东西的箱子 15 | public COIFarmerCreator(List chestsLocation) { 16 | super(); 17 | this.chestsLocation = chestsLocation; 18 | } 19 | 20 | // 收集够这些资源就回去,默认5个 21 | private Integer resourceLimitToBack = 5; 22 | 23 | // 收集的物资存放箱子的位置,可以有多个 24 | private List chestsLocation; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/npc/COIMinerCreator.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.npc; 2 | 3 | import com.mcylm.coi.realm.model.COINpc; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import org.bukkit.Location; 7 | 8 | import java.util.List; 9 | 10 | @EqualsAndHashCode(callSuper = true) 11 | @Data 12 | public class COIMinerCreator extends COINpc { 13 | 14 | // 必须要有装东西的箱子 15 | public COIMinerCreator(List chestsLocation) { 16 | super(); 17 | this.chestsLocation = chestsLocation; 18 | } 19 | 20 | // 收集够这些资源就回去,默认64个 21 | private Integer resourceLimitToBack = 64; 22 | 23 | // 收集的物资存放箱子的位置,可以有多个 24 | private List chestsLocation; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/npc/COISmithCreator.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.npc; 2 | 3 | import com.mcylm.coi.realm.model.COINpc; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import org.bukkit.Location; 7 | 8 | import java.util.List; 9 | 10 | @EqualsAndHashCode(callSuper = true) 11 | @Data 12 | public class COISmithCreator extends COINpc { 13 | 14 | // 待构建 15 | public COISmithCreator() { 16 | super(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/npc/COISoldierCreator.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.npc; 2 | 3 | import com.mcylm.coi.realm.model.COINpc; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | 7 | @EqualsAndHashCode(callSuper = true) 8 | @Data 9 | public class COISoldierCreator extends COINpc { 10 | 11 | @Override 12 | public double getAlertRadius() { 13 | return 20; 14 | } 15 | 16 | public COISoldierCreator(){ 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/npc/impl/COISmith.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.npc.impl; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.enums.COIBuildingType; 5 | import com.mcylm.coi.realm.model.COINpc; 6 | import com.mcylm.coi.realm.runnable.TaskRunnable; 7 | import com.mcylm.coi.realm.tools.building.COIBuilding; 8 | import com.mcylm.coi.realm.tools.npc.COIMinerCreator; 9 | import com.mcylm.coi.realm.utils.ChestUtils; 10 | import com.mcylm.coi.realm.utils.InventoryUtils; 11 | import com.mcylm.coi.realm.utils.ItemUtils; 12 | import com.mcylm.coi.realm.utils.WearUtils; 13 | import net.citizensnpcs.api.npc.BlockBreaker; 14 | import org.bukkit.Bukkit; 15 | import org.bukkit.Effect; 16 | import org.bukkit.Location; 17 | import org.bukkit.Material; 18 | import org.bukkit.block.Block; 19 | import org.bukkit.block.BlockState; 20 | import org.bukkit.block.Container; 21 | import org.bukkit.block.data.Ageable; 22 | import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftMerchant; 23 | import org.bukkit.entity.Entity; 24 | import org.bukkit.entity.Item; 25 | import org.bukkit.entity.LivingEntity; 26 | import org.bukkit.inventory.Inventory; 27 | import org.bukkit.inventory.ItemStack; 28 | import org.bukkit.inventory.Merchant; 29 | import org.bukkit.inventory.MerchantRecipe; 30 | import org.bukkit.inventory.meta.ItemMeta; 31 | import org.bukkit.scheduler.BukkitRunnable; 32 | 33 | import java.util.*; 34 | 35 | /** 36 | * 铁匠 37 | * 自己本身会出售一些实用的东西 38 | */ 39 | public class COISmith extends COIEntity { 40 | 41 | public COISmith(COINpc npcCreator) { 42 | super(npcCreator); 43 | } 44 | 45 | 46 | @Override 47 | public void move(){ 48 | super.move(); 49 | 50 | // 看最近的玩家 51 | lookNearestPlayer(); 52 | 53 | if(!isTooHungryToWork()){ 54 | Location center = getCoiNpc().getSpawnLocation().clone(); 55 | center.setX(center.getX() + 0.5); 56 | center.setZ(center.getZ() + 0.5); 57 | findPath(center); 58 | } 59 | 60 | } 61 | 62 | @Override 63 | public int delayTick() { 64 | return 10; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/npc/impl/monster/COIPillager.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.npc.impl.monster; 2 | 3 | import com.mcylm.coi.realm.tools.npc.monster.COIPillagerCreator; 4 | import com.mcylm.coi.realm.utils.LoggerUtils; 5 | import org.bukkit.Location; 6 | import org.bukkit.Material; 7 | import org.bukkit.inventory.ItemStack; 8 | 9 | public class COIPillager extends COIMonster { 10 | 11 | 12 | public COIPillager(COIPillagerCreator npcCreator) { 13 | super(npcCreator); 14 | } 15 | 16 | @Override 17 | public int getDamage() { 18 | return 5; 19 | } 20 | 21 | @Override 22 | public int delayTick() { 23 | return 5; 24 | } 25 | 26 | @Override 27 | public void spawn(Location location) { 28 | 29 | super.spawn(location); 30 | 31 | setHunger(40); 32 | // 初始化背包 33 | getCoiNpc().getInventory().addItem(new ItemStack(Material.CROSSBOW)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/npc/impl/monster/COIPillagerCaptain.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.npc.impl.monster; 2 | 3 | 4 | import com.mcylm.coi.realm.tools.npc.monster.COIPillagerCreator; 5 | 6 | // 小队队长 属于精英怪 7 | public class COIPillagerCaptain extends COIPillager { 8 | public COIPillagerCaptain(COIPillagerCreator npcCreator) { 9 | super(npcCreator); 10 | } 11 | 12 | @Override 13 | public int getDamage() { 14 | return 10; 15 | } 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/npc/monster/COIMonsterCreator.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.npc.monster; 2 | 3 | import com.mcylm.coi.realm.model.COINpc; 4 | import com.mcylm.coi.realm.tools.building.COIBuilding; 5 | import org.bukkit.entity.EntityType; 6 | 7 | public abstract class COIMonsterCreator extends COINpc { 8 | public COIMonsterCreator() { 9 | super(); 10 | setNpcType(EntityType.ZOMBIE); 11 | } 12 | 13 | public abstract void createMonster(COIBuilding building); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/npc/monster/COIPillagerCreator.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.npc.monster; 2 | 3 | import com.mcylm.coi.realm.model.COINpc; 4 | import com.mcylm.coi.realm.tools.attack.impl.PatrolGoal; 5 | import com.mcylm.coi.realm.tools.attack.team.AttackTeam; 6 | import com.mcylm.coi.realm.tools.building.COIBuilding; 7 | import com.mcylm.coi.realm.tools.npc.impl.monster.COIPillager; 8 | import com.mcylm.coi.realm.utils.GUIUtils; 9 | import lombok.Getter; 10 | import lombok.Setter; 11 | import org.bukkit.Material; 12 | import org.bukkit.entity.EntityType; 13 | import org.bukkit.inventory.Inventory; 14 | import org.bukkit.inventory.ItemStack; 15 | 16 | import java.util.HashSet; 17 | import java.util.List; 18 | import java.util.Set; 19 | 20 | public class COIPillagerCreator extends COIMonsterCreator{ 21 | @Setter 22 | @Getter 23 | private AttackTeam attackteam; 24 | public COIPillagerCreator(AttackTeam attackteam) { 25 | setNpcType(EntityType.PILLAGER); 26 | this.attackteam = attackteam; 27 | } 28 | 29 | public static COIPillagerCreator initCOIPillagerCreator(AttackTeam attackteam) { 30 | // 背包内的物品 31 | Inventory inventory = GUIUtils.createNpcInventory(3); 32 | // 改在spawn方法里面了 33 | // inventory.addItem(new ItemStack(Material.CROSSBOW)); 34 | 35 | // 不破坏方块 36 | Set breakBlockMaterials = new HashSet<>(); 37 | 38 | // 捡起的东西 39 | Set pickItemMaterials = new HashSet<>(); 40 | pickItemMaterials.add("EMERALD"); 41 | 42 | // 将装备默认设为捡起 43 | List clothes = COINpc.CLOTHES; 44 | for(Material clothesType : clothes){ 45 | pickItemMaterials.add(clothesType.name()); 46 | } 47 | COIPillagerCreator npcCreator = new COIPillagerCreator(attackteam); 48 | npcCreator.setInventory(inventory); 49 | npcCreator.setAggressive(true); 50 | npcCreator.setAlertRadius(10); 51 | npcCreator.setBreakBlockMaterials(breakBlockMaterials); 52 | npcCreator.setName("掠夺者"); 53 | npcCreator.setLevel(1); 54 | npcCreator.setPickItemMaterials(pickItemMaterials); 55 | return npcCreator; 56 | } 57 | 58 | @Override 59 | public void createMonster(COIBuilding building) { 60 | COIPillager pillager = new COIPillager(this); 61 | pillager.spawn(getSpawnLocation()); 62 | 63 | pillager.setGoal(new PatrolGoal(pillager)); //TODO 使用TeamFollowGoal 64 | pillager.getGoal().start(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/selection/Selector.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.selection; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.entity.Player; 5 | 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | public interface Selector { 10 | 11 | Map selectors = new ConcurrentHashMap<>(); 12 | 13 | boolean isStop(); 14 | 15 | void stop(boolean sendMsg); 16 | 17 | void selectLocation(Location loc); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/team/Team.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.team; 2 | 3 | import com.mcylm.coi.realm.enums.COIBuildingType; 4 | import com.mcylm.coi.realm.enums.COIScoreType; 5 | import com.mcylm.coi.realm.model.COIScore; 6 | import com.mcylm.coi.realm.tools.building.COIBuilding; 7 | import com.mcylm.coi.realm.tools.team.impl.COITeam; 8 | import org.bukkit.entity.Player; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * 小队抽象层 14 | */ 15 | public interface Team { 16 | 17 | // 创建全部小队 18 | boolean join(Player player); 19 | 20 | // 通过建筑类型获取当前小队所建造的建筑 21 | List getBuildingByType(COIBuildingType type); 22 | 23 | // 给当前小队增加或者减少积分 24 | void addScore(COIScoreType type,Player player); 25 | 26 | // 被另一个队伍击败 27 | void defeatedBy(Player player,COITeam team); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/tools/trait/DisguiseTrait.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.tools.trait; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import me.libraryaddict.disguise.disguisetypes.Disguise; 6 | import net.citizensnpcs.api.trait.Trait; 7 | import org.bukkit.entity.Entity; 8 | 9 | import java.util.Optional; 10 | 11 | 12 | public class DisguiseTrait extends Trait { 13 | 14 | private Disguise disguise; 15 | private boolean appliedSkin = false; 16 | 17 | public void setDisguise(Disguise disguise) { 18 | this.disguise = disguise; 19 | disguise(); 20 | } 21 | public DisguiseTrait(){ 22 | super("Disguise"); 23 | } 24 | 25 | public Optional getDisguise() { 26 | return Optional.ofNullable(this.disguise); 27 | } 28 | 29 | @Override 30 | public void onSpawn() { 31 | disguise(); 32 | } 33 | 34 | private void disguise() { 35 | 36 | if (getNPC() == null || !getNPC().isSpawned()) { 37 | return; 38 | } 39 | 40 | // citizens will respawn the NPC after changing its skin 41 | // not checking this will cause an endless loop 42 | if (appliedSkin) return; 43 | 44 | getDisguise().ifPresent(disguise -> { 45 | appliedSkin = true; 46 | Entity entity = getNPC().getEntity(); 47 | disguise.setEntity(entity); 48 | disguise.setDynamicName(true); 49 | disguise.startDisguise(); 50 | }); 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/ChestUtils.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils; 2 | 3 | import com.comphenix.protocol.PacketType; 4 | import com.comphenix.protocol.ProtocolLibrary; 5 | import com.comphenix.protocol.ProtocolManager; 6 | import com.comphenix.protocol.events.PacketContainer; 7 | import com.comphenix.protocol.wrappers.BlockPosition; 8 | import org.bukkit.Location; 9 | import org.bukkit.block.Block; 10 | import org.bukkit.entity.Player; 11 | 12 | public class ChestUtils { 13 | 14 | /** 15 | * 开关箱子动画 16 | * @param block 17 | * @param opened 18 | */ 19 | public static void setChestOpened(Block block, boolean opened) { 20 | PacketContainer libPacket = new PacketContainer(PacketType.Play.Server.BLOCK_ACTION); 21 | libPacket.getBlockPositionModifier().write(0, new BlockPosition(block.getX(), block.getY(), block.getZ())); 22 | libPacket.getIntegers().write(0, 1); 23 | libPacket.getIntegers().write(1, opened ? 1 : 0); 24 | libPacket.getBlocks().write(0, block.getType()); 25 | int distanceSquared = 64 * 64; 26 | Location loc = block.getLocation(); 27 | ProtocolManager manager = ProtocolLibrary.getProtocolManager(); 28 | for (Player player : block.getWorld().getPlayers()) { 29 | if (player.getLocation().distanceSquared(loc) < distanceSquared) { 30 | manager.sendServerPacket(player, libPacket); 31 | } 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/DamageUtils.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils; 2 | 3 | import com.mcylm.coi.realm.model.COINpc; 4 | 5 | import java.util.Random; 6 | 7 | /** 8 | * 伤害计算工具类 9 | */ 10 | public class DamageUtils { 11 | 12 | public static double getRandomDamage(COINpc npc){ 13 | Random rand = new Random(); 14 | 15 | double minDamage = npc.getMinDamage() + npc.getLevel(); 16 | double maxDamage = npc.getMaxDamage() + npc.getLevel(); 17 | 18 | // 在攻击伤害范围内,随机产生伤害 19 | double damage = rand.nextInt((int) ((maxDamage + 1) - minDamage)) + minDamage; 20 | 21 | return damage; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.PrintStream; 6 | 7 | public class FileUtils { 8 | 9 | //写入文件 10 | public static boolean saveFile(String string,String path) { 11 | 12 | PrintStream stream=null; 13 | try { 14 | 15 | stream=new PrintStream(path);//写入的文件path 16 | stream.print(string);//写入的字符串 17 | return true; 18 | } catch (FileNotFoundException e) { 19 | e.printStackTrace(); 20 | } 21 | return false; 22 | } 23 | 24 | public static String createFileByPath(String path){ 25 | try{ 26 | 27 | File file = new File(path); 28 | File fileParent = file.getParentFile(); 29 | 30 | if(!fileParent.exists()){ 31 | fileParent.mkdirs(); 32 | } 33 | 34 | if(file.exists()){ 35 | return "文件已存在,不能重复创建"; 36 | } 37 | file.createNewFile(); 38 | 39 | 40 | }catch(Exception e){ 41 | System.out.println(e.getMessage()); 42 | } 43 | return "文件创建成功"; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/InventoryUtils.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils; 2 | 3 | 4 | import com.mcylm.coi.realm.Entry; 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.GameMode; 7 | import org.bukkit.Material; 8 | import org.bukkit.entity.Player; 9 | import org.bukkit.event.inventory.InventoryType; 10 | import org.bukkit.inventory.Inventory; 11 | import org.bukkit.inventory.ItemStack; 12 | import org.checkerframework.checker.nullness.qual.NonNull; 13 | 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | public class InventoryUtils { 18 | private static final Map testInventories = new HashMap<>(); 19 | public static boolean canInventoryHoldItem(Inventory inventory, ItemStack... itemStacks) { 20 | Inventory testInventory = testInventories.get(inventory.getType()); 21 | if (testInventory == null) { 22 | testInventory = Bukkit.createInventory(null, inventory.getType()); 23 | testInventories.put(inventory.getType(), testInventory); 24 | } 25 | testInventory.clear(); 26 | ItemStack[] contents = inventory.getContents(); 27 | testInventory.setContents(contents); 28 | return testInventory.addItem(itemStacks).isEmpty(); 29 | } 30 | 31 | /** 32 | * 扣减玩家背包里的资源数量 33 | * @param player 34 | * @param amount 35 | * @return 36 | */ 37 | public static boolean deductionResources(Player player, int amount) { 38 | 39 | if(player != null){ 40 | if(player.isOp() && player.getGameMode().equals(GameMode.CREATIVE)){ 41 | return true; 42 | } 43 | }else{ 44 | return false; 45 | } 46 | 47 | 48 | int playerHadResource = getPlayerHadResource(player); 49 | 50 | // 如果玩家手里的资源数量足够 51 | if (playerHadResource >= amount) { 52 | 53 | // 扣减物品 54 | ItemStack[] contents = 55 | player.getInventory().getContents(); 56 | 57 | // 剩余所需扣减资源数量 58 | int deductionCount = amount; 59 | 60 | // 资源类型 61 | Material material = getResourceType(); 62 | for (ItemStack itemStack : contents) { 63 | 64 | if (itemStack == null) { 65 | continue; 66 | } 67 | 68 | // 是资源物品才扣减 69 | if (itemStack.getType().equals(material)) { 70 | // 如果当前物品的堆叠数量大于所需资源,就只扣减数量 71 | if (itemStack.getAmount() > deductionCount) { 72 | itemStack.setAmount(itemStack.getAmount() - deductionCount); 73 | return true; 74 | } 75 | 76 | // 如果当前物品的堆叠数量等于所需资源,就删物品 77 | if (itemStack.getAmount() == deductionCount) { 78 | player.getInventory().removeItem(itemStack); 79 | player.updateInventory(); 80 | return true; 81 | } 82 | 83 | // 如果物品的堆叠数量小于所需资源,就删物品,同时计数 84 | if (itemStack.getAmount() < deductionCount) { 85 | // 减去当前物品的库存 86 | deductionCount = deductionCount - itemStack.getAmount(); 87 | player.getInventory().removeItem(itemStack); 88 | player.updateInventory(); 89 | } 90 | } 91 | 92 | 93 | } 94 | 95 | } else 96 | return false; 97 | 98 | return false; 99 | } 100 | 101 | /** 102 | * 获取玩家背包里的资源 103 | * 104 | * @return 105 | */ 106 | public static int getPlayerHadResource(Player player) { 107 | 108 | @NonNull ItemStack[] contents = 109 | player.getInventory().getContents(); 110 | 111 | Material material = getResourceType(); 112 | if (material == null) { 113 | return 0; 114 | } 115 | 116 | int num = 0; 117 | 118 | for (ItemStack itemStack : contents) { 119 | 120 | if (itemStack == null) { 121 | continue; 122 | } 123 | 124 | if (itemStack.getType().equals(material)) { 125 | num = num + itemStack.getAmount(); 126 | } 127 | } 128 | 129 | return num; 130 | 131 | } 132 | 133 | public static Material getResourceType() { 134 | String materialName = Entry.getInstance().getConfig().getString("game.building.material"); 135 | 136 | return Material.getMaterial(materialName); 137 | 138 | } 139 | 140 | 141 | 142 | } 143 | 144 | 145 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils; 2 | 3 | import java.io.*; 4 | 5 | public class JsonUtils { 6 | 7 | //读取json文件 8 | public static String readJsonFile(String fileName) { 9 | String jsonStr = ""; 10 | try { 11 | File jsonFile = new File(fileName); 12 | FileReader fileReader = new FileReader(jsonFile); 13 | Reader reader = new InputStreamReader(new FileInputStream(jsonFile),"utf-8"); 14 | int ch = 0; 15 | StringBuffer sb = new StringBuffer(); 16 | while ((ch = reader.read()) != -1) { 17 | sb.append((char) ch); 18 | } 19 | fileReader.close(); 20 | reader.close(); 21 | jsonStr = sb.toString(); 22 | return jsonStr; 23 | } catch (IOException e) { 24 | e.printStackTrace(); 25 | return null; 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/LoggerUtils.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import com.mcylm.coi.realm.enums.COIServerMode; 5 | import me.lucko.helper.text.Component; 6 | import net.md_5.bungee.api.ChatMessageType; 7 | import net.md_5.bungee.api.chat.TextComponent; 8 | import org.apache.commons.lang.StringUtils; 9 | import org.bukkit.Bukkit; 10 | import org.bukkit.command.CommandSender; 11 | import org.bukkit.entity.NPC; 12 | import org.bukkit.entity.Player; 13 | import org.bukkit.scheduler.BukkitRunnable; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | public class LoggerUtils { 19 | 20 | public static void log(String msg){ 21 | Entry.getInstance().getLogger().info("["+Entry.PREFIX+" INFO] "+replaceColor(msg)); 22 | } 23 | 24 | public static void debug(String msg){ 25 | //只有开发模式才输出的日志 26 | if(COIServerMode.DEVELOP.getCode().equals(Entry.SERVER_MODE)){ 27 | Entry.getInstance().getLogger().info("["+Entry.PREFIX+" DEBUG] "+replaceColor(msg)); 28 | } 29 | 30 | } 31 | 32 | public static void sendMessage(String msg, CommandSender player){ 33 | 34 | if(player == null){ 35 | return; 36 | } 37 | 38 | player.sendMessage("§f[§b§l"+Entry.PREFIX+"§f] §7"+replaceColor(msg)); 39 | } 40 | 41 | public static void sendMessage(String msg, Player player){ 42 | 43 | if(player == null){ 44 | return; 45 | } 46 | 47 | if(player.isOnline()){ 48 | player.sendMessage("§f[§b§l"+Entry.PREFIX+"§f] §7"+replaceColor(msg)); 49 | } 50 | } 51 | 52 | public static void sendAllChatMessage(String msg, Player player){ 53 | 54 | if(player == null){ 55 | return; 56 | } 57 | 58 | if(player.isOnline()){ 59 | player.sendMessage("§f[§e全局 §c/all§f] §7"+replaceColor(msg)); 60 | } 61 | } 62 | 63 | public static void sendTeamChatMessage(String msg, Player player){ 64 | 65 | if(player == null){ 66 | return; 67 | } 68 | 69 | if(player.isOnline()){ 70 | player.sendMessage("§f[§b队内§f] §7"+replaceColor(msg)); 71 | } 72 | } 73 | 74 | public static String replaceColor(String msg){ 75 | return msg.replace("&","§"); 76 | } 77 | 78 | public static void sendActionbar(Player player, String message) { 79 | 80 | if(player != null && StringUtils.isNotBlank(player.getName())) { 81 | player = Bukkit.getPlayer(player.getName()); 82 | } 83 | 84 | if (player == null || message == null || !player.isOnline()) return; 85 | player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(replaceColor(message))); 86 | 87 | } 88 | 89 | public static void sendActionbar( String message,Player player) { 90 | sendActionbar(player,message); 91 | } 92 | 93 | public static void broadcastMessage(String message){ 94 | 95 | for(Player player : Bukkit.getOnlinePlayers()){ 96 | if(player.isOnline()){ 97 | player.sendMessage("§f[§a公告§f] §7"+replaceColor(message)); 98 | } 99 | } 100 | } 101 | 102 | 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/MapUtils.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.util.zip.ZipEntry; 7 | import java.util.zip.ZipInputStream; 8 | 9 | 10 | public class MapUtils { 11 | 12 | public static void extractMap(File zipFile, File destDir) throws Exception { 13 | // 创建目标目录 14 | if (!destDir.exists()) { 15 | destDir.mkdir(); 16 | } 17 | 18 | // 打开 ZIP 文件 19 | ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFile)); 20 | 21 | extractFile(zipIn, destDir.getAbsolutePath()); 22 | zipIn.close(); 23 | } 24 | 25 | private static void extractFile(ZipInputStream zipIn, String filePath) throws Exception { 26 | // 创建输出文件流 27 | FileOutputStream fos = new FileOutputStream(filePath); 28 | 29 | // 从 ZIP 文件中读取数据并写入输出文件流 30 | byte[] buffer = new byte[4096]; 31 | int bytesRead; 32 | while ((bytesRead = zipIn.read(buffer)) != -1) { 33 | fos.write(buffer, 0, bytesRead); 34 | } 35 | 36 | // 关闭输出文件流 37 | fos.close(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/ScheduleUtils.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.ScheduledExecutorService; 7 | 8 | public class ScheduleUtils { 9 | 10 | @Getter 11 | private static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(4); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/ServerUtils.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils; 2 | 3 | import com.mcylm.coi.realm.Entry; 4 | import org.bukkit.entity.Player; 5 | 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.DataOutputStream; 8 | 9 | public class ServerUtils { 10 | 11 | public static void teleport(Player p, String server) { 12 | if (p != null) { 13 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 14 | DataOutputStream out = new DataOutputStream(baos); 15 | try { 16 | out.writeUTF("Connect"); 17 | out.writeUTF(server); 18 | } catch (Exception exception) {} 19 | p.sendPluginMessage(Entry.getInstance(), "BungeeCord", baos.toByteArray()); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/SkullUtils.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils; 2 | 3 | import com.mojang.authlib.GameProfile; 4 | import com.mojang.authlib.properties.Property; 5 | import org.bukkit.Material; 6 | import org.bukkit.SkullType; 7 | import org.bukkit.inventory.ItemStack; 8 | import org.bukkit.inventory.meta.SkullMeta; 9 | 10 | import java.lang.reflect.Field; 11 | 12 | public class SkullUtils { 13 | 14 | public static ItemStack createPlayerHead(String url) { 15 | ItemStack head = new ItemStack(Material.PLAYER_HEAD, 1, (short) SkullType.PLAYER.ordinal()); 16 | if (url.isEmpty()) return head; 17 | 18 | SkullMeta headMeta = (SkullMeta) head.getItemMeta(); 19 | GameProfile profile = new GameProfile(java.util.UUID.randomUUID(), null); 20 | profile.getProperties().put("textures", new Property("textures", url)); 21 | 22 | Field profileField = null; 23 | try { 24 | profileField = headMeta.getClass().getDeclaredField("profile"); 25 | profileField.setAccessible(true); 26 | profileField.set(headMeta, profile); 27 | } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) { 28 | e.printStackTrace(); 29 | } 30 | 31 | head.setItemMeta(headMeta); 32 | return head; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/TimeUtils.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils; 2 | 3 | public class TimeUtils { 4 | 5 | public static String formatDateTime(long mss) { 6 | String DateTimes = null; 7 | long days = mss / ( 60 * 60 * 24); 8 | long hours = (mss % ( 60 * 60 * 24)) / (60 * 60); 9 | long minutes = (mss % ( 60 * 60)) /60; 10 | long seconds = mss % 60; 11 | if(days>0){ 12 | DateTimes= days + "天" + hours + "小时" + minutes + "分钟" 13 | + seconds + "秒"; 14 | }else if(hours>0){ 15 | DateTimes=hours + "小时" + minutes + "分钟" 16 | + seconds + "秒"; 17 | }else if(minutes>0){ 18 | DateTimes=minutes + "分钟" 19 | + seconds + "秒"; 20 | }else{ 21 | DateTimes=seconds + "秒"; 22 | } 23 | 24 | return DateTimes; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/WearUtils.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils; 2 | 3 | import org.bukkit.Material; 4 | import org.bukkit.inventory.ItemStack; 5 | 6 | public class WearUtils { 7 | 8 | public static boolean canWearOnHead(ItemStack itemStack) { 9 | if (itemStack == null || itemStack.getType() == Material.AIR) { 10 | return false; 11 | } 12 | Material type = itemStack.getType(); 13 | return type == Material.LEATHER_HELMET || type == Material.CHAINMAIL_HELMET || 14 | type == Material.IRON_HELMET || type == Material.GOLDEN_HELMET || 15 | type == Material.DIAMOND_HELMET || type == Material.TURTLE_HELMET || 16 | type == Material.NETHERITE_HELMET; 17 | } 18 | 19 | // 判断物品是否可以穿在身上 20 | public static boolean canWearOnBody(ItemStack itemStack) { 21 | if (itemStack == null || itemStack.getType() == Material.AIR) { 22 | return false; 23 | } 24 | Material material = itemStack.getType(); 25 | return material == Material.LEATHER_CHESTPLATE 26 | || material == Material.CHAINMAIL_CHESTPLATE 27 | || material == Material.IRON_CHESTPLATE 28 | || material == Material.GOLDEN_CHESTPLATE 29 | || material == Material.DIAMOND_CHESTPLATE 30 | || material == Material.NETHERITE_CHESTPLATE; 31 | } 32 | 33 | // 判断物品是否可以穿在腿上 34 | public static boolean canWearOnLegs(ItemStack itemStack) { 35 | if (itemStack == null || itemStack.getType() == Material.AIR) { 36 | return false; 37 | } 38 | Material material = itemStack.getType(); 39 | return material == Material.LEATHER_LEGGINGS 40 | || material == Material.CHAINMAIL_LEGGINGS 41 | || material == Material.IRON_LEGGINGS 42 | || material == Material.GOLDEN_LEGGINGS 43 | || material == Material.DIAMOND_LEGGINGS 44 | || material == Material.NETHERITE_LEGGINGS 45 | ; 46 | } 47 | 48 | // 判断物品是否可以穿在脚上 49 | public static boolean canWearOnFeet(ItemStack itemStack) { 50 | if (itemStack == null || itemStack.getType() == Material.AIR) { 51 | return false; 52 | } 53 | Material material = itemStack.getType(); 54 | return material == Material.LEATHER_BOOTS 55 | || material == Material.CHAINMAIL_BOOTS 56 | || material == Material.IRON_BOOTS 57 | || material == Material.GOLDEN_BOOTS 58 | || material == Material.DIAMOND_BOOTS 59 | || material == Material.NETHERITE_BOOTS 60 | ; 61 | } 62 | 63 | public static boolean canHoldInHand(ItemStack itemStack) { 64 | if (itemStack == null || itemStack.getType() == Material.AIR) { 65 | return false; 66 | } 67 | return itemStack.getType() == Material.DIAMOND_SWORD 68 | || itemStack.getType() == Material.STONE_SWORD 69 | || itemStack.getType() == Material.WOODEN_SWORD 70 | || itemStack.getType() == Material.GOLDEN_SWORD 71 | || itemStack.getType() == Material.IRON_SWORD 72 | || itemStack.getType() == Material.NETHERITE_SWORD 73 | //斧头 74 | || itemStack.getType() == Material.DIAMOND_AXE 75 | || itemStack.getType() == Material.GOLDEN_AXE 76 | || itemStack.getType() == Material.IRON_AXE 77 | || itemStack.getType() == Material.NETHERITE_AXE 78 | || itemStack.getType() == Material.STONE_AXE 79 | || itemStack.getType() == Material.WOODEN_AXE 80 | //镐子 81 | || itemStack.getType() == Material.DIAMOND_PICKAXE 82 | || itemStack.getType() == Material.GOLDEN_PICKAXE 83 | || itemStack.getType() == Material.IRON_PICKAXE 84 | || itemStack.getType() == Material.NETHERITE_PICKAXE 85 | || itemStack.getType() == Material.STONE_PICKAXE 86 | || itemStack.getType() == Material.WOODEN_PICKAXE 87 | //锄头 88 | || itemStack.getType() == Material.DIAMOND_HOE 89 | || itemStack.getType() == Material.GOLDEN_HOE 90 | || itemStack.getType() == Material.IRON_HOE 91 | || itemStack.getType() == Material.NETHERITE_HOE 92 | || itemStack.getType() == Material.STONE_HOE 93 | || itemStack.getType() == Material.WOODEN_HOE 94 | // 弩 95 | || itemStack.getType() == Material.CROSSBOW 96 | // Bow 97 | || itemStack.getType() == Material.BOW 98 | 99 | ; 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/particle/ParticleRect.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils.particle; 2 | 3 | import com.destroystokyo.paper.ParticleBuilder; 4 | import org.bukkit.Location; 5 | import org.bukkit.Particle; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.util.Vector; 8 | 9 | import java.util.ArrayList; 10 | 11 | public class ParticleRect { 12 | 13 | ArrayList sides = new ArrayList(); 14 | Location start; 15 | 16 | public ParticleRect(Location start, double width, double length,double height){ 17 | this.start = start; 18 | Vector A = new Vector(0,0,0); 19 | Vector B = new Vector(length,0,0); 20 | Vector C = new Vector(0,0,width); 21 | Vector D = new Vector(0,height,0); 22 | Vector E = new Vector(0,height,width); 23 | Vector F = new Vector(length,height,0); 24 | Vector G = new Vector(length,0,width); 25 | sides.add(new ParticlePoint(A,B)); 26 | sides.add(new ParticlePoint(A,C)); 27 | sides.add(new ParticlePoint(A,D)); 28 | sides.add(new ParticlePoint(C,D)); 29 | sides.add(new ParticlePoint(B,D)); 30 | sides.add(new ParticlePoint(C,B)); 31 | sides.add(new ParticlePoint(B,C)); 32 | sides.add(new ParticlePoint(D,C)); 33 | sides.add(new ParticlePoint(D,B)); 34 | sides.add(new ParticlePoint(E,B)); 35 | sides.add(new ParticlePoint(F,C)); 36 | sides.add(new ParticlePoint(G,D)); 37 | } 38 | 39 | public Vector getPosition(double blocksAway, Vector origin, Vector direction) { 40 | return origin.clone().add(direction.clone().normalize().multiply(blocksAway)); 41 | } 42 | 43 | public ArrayList traverse(Vector origin, Vector direction) { 44 | ArrayList positions = new ArrayList<>(); 45 | for (double d = 0; d <= direction.length(); d += 1) { 46 | positions.add(getPosition(d,origin,direction)); 47 | } 48 | return positions; 49 | } 50 | 51 | public void draw(ParticleBuilder particle, Player p){ 52 | for(ParticlePoint point : sides){ 53 | for(Vector position : traverse(point.origin,point.direction)){ 54 | position = start.toVector().clone().add(position); 55 | particle.location(position.toLocation(start.getWorld())).spawn(); 56 | 57 | } 58 | } 59 | } 60 | 61 | private class ParticlePoint { 62 | Vector origin,direction; 63 | ParticlePoint(Vector origin, Vector direction) { 64 | this.origin = origin; 65 | this.direction = direction; 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/region/Region.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils.region; 2 | 3 | 4 | import com.mcylm.coi.realm.utils.LoggerUtils; 5 | import org.bukkit.Location; 6 | import org.bukkit.World; 7 | import org.bukkit.block.Block; 8 | 9 | import java.util.HashSet; 10 | import java.util.Set; 11 | 12 | public class Region { 13 | 14 | private World world; 15 | 16 | private double maxX; 17 | private double maxY; 18 | private double maxZ; 19 | 20 | private double minX; 21 | private double minY; 22 | private double minZ; 23 | 24 | 25 | public Region(Location firstPoint, Location secondPoint) { 26 | world = firstPoint.getWorld(); 27 | 28 | maxX = Math.max(firstPoint.getX(), secondPoint.getX()); 29 | maxY = Math.max(firstPoint.getY(), secondPoint.getY()); 30 | maxZ = Math.max(firstPoint.getZ(), secondPoint.getZ()); 31 | 32 | minX = Math.min(firstPoint.getX(), secondPoint.getX()); 33 | minY = Math.min(firstPoint.getY(), secondPoint.getY()); 34 | minZ = Math.min(firstPoint.getZ(), secondPoint.getZ()); 35 | } 36 | 37 | public boolean isInRegion(Location loc) { 38 | return loc.getWorld() == world 39 | && loc.getX() > minX && loc.getX() < maxX 40 | && loc.getY() > minY && loc.getY() < maxY 41 | && loc.getZ() > minZ && loc.getZ() < maxZ; 42 | } 43 | 44 | public Set getBlocks() { 45 | Set blocks = new HashSet<>(); 46 | for (double x = minX; x < maxX; x++) { 47 | for (double y = minY; y < maxY; y++) { 48 | for (double z = minZ; z < maxZ; z++) { 49 | blocks.add(new Location(world, x, y, z).getBlock()); 50 | } 51 | } 52 | } 53 | return blocks; 54 | } 55 | } -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/rotation/Rotation.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils.rotation; 2 | 3 | public enum Rotation { 4 | 5 | CW_90(90), 6 | CW_180(180), 7 | CCW_90(270), 8 | NONE(0); 9 | private final int degrees; 10 | 11 | Rotation(int degrees) { 12 | this.degrees = degrees; 13 | } 14 | 15 | public static Rotation fromDegrees(int deg) { 16 | return switch(Math.floorMod(deg, 360)) { 17 | case 0 -> Rotation.NONE; 18 | case 90 -> Rotation.CW_90; 19 | case 180 -> Rotation.CW_180; 20 | case 270 -> Rotation.CCW_90; 21 | default -> throw new IllegalArgumentException(); 22 | }; 23 | } 24 | 25 | public Rotation inverse() { 26 | return switch(this) { 27 | case NONE -> NONE; 28 | case CCW_90 -> CW_90; 29 | case CW_90 -> CCW_90; 30 | case CW_180 -> CW_180; 31 | }; 32 | } 33 | 34 | public Rotation rotate(Rotation rotation) { 35 | return fromDegrees(this.getDegrees() + rotation.getDegrees()); 36 | } 37 | 38 | public int getDegrees() { 39 | return degrees; 40 | } 41 | 42 | public enum Axis { 43 | X, 44 | Y, 45 | Z 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/mcylm/coi/realm/utils/rotation/Vector2Int.java: -------------------------------------------------------------------------------- 1 | package com.mcylm.coi.realm.utils.rotation; 2 | 3 | public class Vector2Int { 4 | private static final Vector2Int ZERO = new Vector2Int(0, 0); 5 | private static final Vector2Int UNIT = new Vector2Int(0, 1); 6 | protected int x; 7 | protected int z; 8 | 9 | protected Vector2Int(int x, int z) { 10 | this.x = x; 11 | this.z = z; 12 | } 13 | 14 | public static Vector2Int zero() { 15 | return ZERO; 16 | } 17 | 18 | public static Vector2Int unit() { 19 | return UNIT; 20 | } 21 | 22 | public static Vector2Int of(int x, int z) { 23 | return new Vector2Int(x, z); 24 | } 25 | 26 | public int getX() { 27 | return x; 28 | } 29 | 30 | public int getZ() { 31 | return z; 32 | } 33 | 34 | public Mutable mutable() { 35 | return new Mutable(x, z); 36 | } 37 | 38 | public Vector2Int rotate(Rotation rotation) { 39 | return switch(rotation) { 40 | case CW_90 -> of(z, -x); 41 | case CCW_90 -> of(-z, x); 42 | case CW_180 -> of(-x, -z); 43 | default -> this; 44 | }; 45 | } 46 | 47 | @Override 48 | public int hashCode() { 49 | return (31 * x) + z; 50 | } 51 | 52 | @Override 53 | public boolean equals(Object obj) { 54 | if(obj instanceof Vector2Int that) { 55 | return this.x == that.x && this.z == that.z; 56 | } 57 | return false; 58 | } 59 | 60 | 61 | public static class Mutable extends Vector2Int { 62 | 63 | protected Mutable(int x, int z) { 64 | super(x, z); 65 | } 66 | 67 | public int getZ() { 68 | return z; 69 | } 70 | 71 | public void setZ(int z) { 72 | this.z = z; 73 | } 74 | 75 | public int getX() { 76 | return x; 77 | } 78 | 79 | public void setX(int x) { 80 | this.x = x; 81 | } 82 | 83 | public Vector2Int immutable() { 84 | return new Vector2Int(x, z); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/resources/assembly.xml: -------------------------------------------------------------------------------- 1 | 2 | jar-with-dependencies 3 | 4 | jar 5 | 6 | false 7 | 8 | 9 | 10 | / 11 | true 12 | true 13 | runtime 14 | 15 | 16 | 17 | / 18 | true 19 | true 20 | system 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/resources/backup/2teammap.json: -------------------------------------------------------------------------------- 1 | { 2 | "veins": [ 3 | { 4 | "structureName": "kuangmai1.structure", 5 | "x": -46, 6 | "y": 88, 7 | "z": -148, 8 | "yaw": 178.66173, 9 | "world": "RTSv2", 10 | "spawnChance": 1.0, 11 | "resetTime": 60 12 | }, 13 | { 14 | "structureName": "kuangmai1.structure", 15 | "x": 4, 16 | "y": 88, 17 | "z": -125, 18 | "yaw": -171.28793, 19 | "world": "RTSv2", 20 | "spawnChance": 1.0, 21 | "resetTime": 60 22 | }, 23 | { 24 | "structureName": "kuangmai1.structure", 25 | "x": 28, 26 | "y": 88, 27 | "z": -110, 28 | "yaw": -163.63757, 29 | "world": "RTSv2", 30 | "spawnChance": 1.0, 31 | "resetTime": 60 32 | }, 33 | { 34 | "structureName": "kuangmai1.structure", 35 | "x": 42, 36 | "y": 88, 37 | "z": -101, 38 | "yaw": -157.03705, 39 | "world": "RTSv2", 40 | "spawnChance": 1.0, 41 | "resetTime": 60 42 | }, 43 | { 44 | "structureName": "kuangmai1.structure", 45 | "x": -24, 46 | "y": 88, 47 | "z": -133, 48 | "yaw": -158.23743, 49 | "world": "RTSv2", 50 | "spawnChance": 1.0, 51 | "resetTime": 60 52 | }, 53 | { 54 | "structureName": "kuangmai1.structure", 55 | "x": -46, 56 | "y": 88, 57 | "z": 167, 58 | "yaw": 178.66173, 59 | "world": "RTSv2", 60 | "spawnChance": 1.0, 61 | "resetTime": 60 62 | }, 63 | { 64 | "structureName": "kuangmai1.structure", 65 | "x": 4, 66 | "y": 88, 67 | "z": 144, 68 | "yaw": -171.28793, 69 | "world": "RTSv2", 70 | "spawnChance": 1.0, 71 | "resetTime": 60 72 | }, 73 | { 74 | "structureName": "kuangmai1.structure", 75 | "x": 28, 76 | "y": 88, 77 | "z": 129, 78 | "yaw": -163.63757, 79 | "world": "RTSv2", 80 | "spawnChance": 1.0, 81 | "resetTime": 60 82 | }, 83 | { 84 | "structureName": "kuangmai1.structure", 85 | "x": 42, 86 | "y": 88, 87 | "z": 120, 88 | "yaw": -157.03705, 89 | "world": "RTSv2", 90 | "spawnChance": 1.0, 91 | "resetTime": 60 92 | }, 93 | { 94 | "structureName": "kuangmai1.structure", 95 | "x": -24, 96 | "y": 88, 97 | "z": 152, 98 | "yaw": -158.23743, 99 | "world": "RTSv2", 100 | "spawnChance": 1.0, 101 | "resetTime": 60 102 | } 103 | ], 104 | "mobSpawnPoints": [ 105 | { 106 | "x": -27, 107 | "y": 88, 108 | "z": -187, 109 | "world": "RTSv2", 110 | "maxRadius": 5, 111 | "handlers": [ 112 | null 113 | ] 114 | }, 115 | { 116 | "x": -67, 117 | "y": 88, 118 | "z": 113, 119 | "world": "RTSv2", 120 | "maxRadius": 5, 121 | "handlers": [ 122 | null 123 | ] 124 | }, 125 | { 126 | "x": -47, 127 | "y": 88, 128 | "z": -196, 129 | "world": "RTSv2", 130 | "maxRadius": 5 131 | }, 132 | { 133 | "x": -1, 134 | "y": 88, 135 | "z": -174, 136 | "world": "RTSv2", 137 | "maxRadius": 5 138 | }, 139 | { 140 | "x": 27, 141 | "y": 88, 142 | "z": -154, 143 | "world": "RTSv2", 144 | "maxRadius": 5 145 | }, 146 | { 147 | "x": -4, 148 | "y": 88, 149 | "z": -170, 150 | "world": "RTSv2", 151 | "maxRadius": 5 152 | }, 153 | { 154 | "x": -19, 155 | "y": 88, 156 | "z": -91, 157 | "world": "RTSv2", 158 | "maxRadius": 5 159 | }, 160 | { 161 | "x": -48, 162 | "y": 88, 163 | "z": -103, 164 | "world": "RTSv2", 165 | "maxRadius": 5 166 | }, 167 | { 168 | "x": -71, 169 | "y": 88, 170 | "z": -118, 171 | "world": "RTSv2", 172 | "maxRadius": 5 173 | } 174 | ] 175 | } -------------------------------------------------------------------------------- /src/main/resources/backup/6teammap.json: -------------------------------------------------------------------------------- 1 | { 2 | "veins": [ 3 | { 4 | "structureName": "kuangmai1.structure", 5 | "x": -46, 6 | "y": 88, 7 | "z": -148, 8 | "yaw": 178.66173, 9 | "world": "RTSv2", 10 | "spawnChance": 1.0, 11 | "resetTime": 60 12 | }, 13 | { 14 | "structureName": "kuangmai1.structure", 15 | "x": 4, 16 | "y": 88, 17 | "z": -125, 18 | "yaw": -171.28793, 19 | "world": "RTSv2", 20 | "spawnChance": 1.0, 21 | "resetTime": 60 22 | }, 23 | { 24 | "structureName": "kuangmai1.structure", 25 | "x": 28, 26 | "y": 88, 27 | "z": -110, 28 | "yaw": -163.63757, 29 | "world": "RTSv2", 30 | "spawnChance": 1.0, 31 | "resetTime": 60 32 | }, 33 | { 34 | "structureName": "kuangmai1.structure", 35 | "x": 42, 36 | "y": 88, 37 | "z": -101, 38 | "yaw": -157.03705, 39 | "world": "RTSv2", 40 | "spawnChance": 1.0, 41 | "resetTime": 60 42 | }, 43 | { 44 | "structureName": "kuangmai1.structure", 45 | "x": -24, 46 | "y": 88, 47 | "z": -133, 48 | "yaw": -158.23743, 49 | "world": "RTSv2", 50 | "spawnChance": 1.0, 51 | "resetTime": 60 52 | }, 53 | { 54 | "structureName": "kuangmai1.structure", 55 | "x": -46, 56 | "y": 88, 57 | "z": 167, 58 | "yaw": 178.66173, 59 | "world": "RTSv2", 60 | "spawnChance": 1.0, 61 | "resetTime": 60 62 | }, 63 | { 64 | "structureName": "kuangmai1.structure", 65 | "x": 4, 66 | "y": 88, 67 | "z": 144, 68 | "yaw": -171.28793, 69 | "world": "RTSv2", 70 | "spawnChance": 1.0, 71 | "resetTime": 60 72 | }, 73 | { 74 | "structureName": "kuangmai1.structure", 75 | "x": 28, 76 | "y": 88, 77 | "z": 129, 78 | "yaw": -163.63757, 79 | "world": "RTSv2", 80 | "spawnChance": 1.0, 81 | "resetTime": 60 82 | }, 83 | { 84 | "structureName": "kuangmai1.structure", 85 | "x": 42, 86 | "y": 88, 87 | "z": 120, 88 | "yaw": -157.03705, 89 | "world": "RTSv2", 90 | "spawnChance": 1.0, 91 | "resetTime": 60 92 | }, 93 | { 94 | "structureName": "kuangmai1.structure", 95 | "x": -24, 96 | "y": 88, 97 | "z": 152, 98 | "yaw": -158.23743, 99 | "world": "RTSv2", 100 | "spawnChance": 1.0, 101 | "resetTime": 60 102 | } 103 | ] 104 | } -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | 2 | # 数据库链接相关信息 3 | address: 'localhost' 4 | port: 3306 5 | database: 'web' 6 | username: 'root' 7 | password: 'A123456789a' 8 | 9 | # 服务器模式 10 | # develop 服务器开发模式:可用于使用各种类型的工具 11 | # release 正式模式:生产环境,不会显示debug信息 12 | server-mode: 'develop' 13 | 14 | # 是否开启bungeecord模式 15 | # 如果开启,游戏结束后会自动将玩家传送回大厅服务器 16 | bungeecord: false 17 | # 大厅服务器名称 18 | bungeecord-lobby: 'imc_lobby' 19 | 20 | # 奖励结算命令(配合其他插件) 21 | reward-command: 'hermes modify %player% %amount% 岛屿冲突奖励结算' 22 | 23 | # 游戏相关的配置参数 24 | game: 25 | # NPC相关的配置 26 | npc: 27 | # NPC的出生点方块类型 28 | spawner-material: 'BEACON' 29 | # 建筑相关的配置 30 | building: 31 | # 建筑材料,建议和矿工挖掘捡起的某样物资一致 32 | material: 'EMERALD' 33 | # 是否开启建筑解锁功能 34 | lock: false 35 | # 游戏开始时,给玩家的一定的数量 36 | when-start-give-player: 64 37 | # 防御塔相关的配置 38 | turret: 39 | # 炮口的方块,激光射线会从这个方块发出 40 | muzzle-material: 'AMETHYST_BLOCK' 41 | # 每个小组最大玩家数量 42 | max-group-players: 5 43 | # 团队总数,最多6个,最少2个 44 | max-teams: 2 45 | # 2个队伍以上时,是纯PVP还是PVPVE 46 | multiple-game-mode: 'PVPVE' 47 | # 最少多少个玩家开始游戏 48 | min-players: 2 49 | # 游戏开始等待时间(秒) 50 | waiting-timer: 120 51 | # 游戏总时长(秒) 52 | gaming-timer: 1200 53 | # 游戏结束后多少秒自动关服(秒) 54 | stopping-timer: 120 55 | # 出生点所在地图 56 | spawn-world: 'RTS' 57 | # 地图的出生点(坐标点),最少数量为队伍数量,可以更多, 58 | # 需要配合地图设计来选点,地点相隔建议取适中的距离 59 | # 如果出生点数量少于队伍数量,则会出现两个队伍共享出生点的奇葩情况 60 | # 格式为:x,y,z 请注意:分隔的逗号是英文的逗号 61 | # 本配置文件的坐标地址是官方默认地图的 62 | # 下载地址:https://待完成 63 | spawn-locations: 64 | - '-75,87,-170' 65 | - '-75,87,156' 66 | # - '155,49,393' 67 | # - '394,49,184' 68 | # - '604,51,148' 69 | # - '910,49,225' 70 | # - '872,49,540' 71 | # - '764,49,814' 72 | # 怪物阵营的出生点(大于等于3个团队时生效) 73 | monster-spawner: '435,49,841' 74 | # 等待大厅世界 75 | lobby-world: 'lobby' 76 | lobby-location: '0.5,65,0.5' 77 | 78 | # 墙体的判定高度 79 | # wall-detect-height: 26 80 | wall-detect-height: 84 81 | # 桥的虚空判定高度 82 | bridge-detect-height: 73 83 | 84 | # NPC可食用的 Material Name 85 | foods: 86 | - 'APPLE' 87 | - 'BREAD' 88 | 89 | # 矿工相关配置信息 90 | miner: 91 | # 矿工会捡起的物品名称 92 | picks: 93 | - 'EMERALD' 94 | - 'APPLE' 95 | - 'BREAD' 96 | 97 | # 矿工会挖掘的物品名称 98 | breaks: 99 | - 'EMERALD_ORE' 100 | 101 | # 建筑升级中跳过的方块 102 | upgrade-skip-blocks: 103 | - "CHEST" 104 | - "BARREL" 105 | - "SHULKER_BOX" 106 | 107 | # 游戏内公告 108 | # 公告间隔时间 109 | notice-interval: 20 110 | # 公告消息内容 111 | notice: 112 | - '&7战局内默认队内聊天,如果需要全局聊天,请使用 &c/all <聊天消息>' 113 | - '&7游戏目标是&c摧毁敌方大本营&7,或者游戏时间结束前&e团队积分大于敌方团队' 114 | - '&7手中的建筑蓝图是用来建造建筑,并产生NPC的,不要再自己去挖矿了,把这种苦差事交给NPC去做吧!' 115 | - '&c铁匠铺&7一定要多升级,他那可有不少好东西' 116 | - '&7攻击型的防御塔的&c建造数量上限等于大本营的等级&7来的,一定要记得升级大本营' 117 | - '&7右侧计分板的&a绿宝石&7是大本营的箱子里面现存的绿宝石数量,记得拿去用哦' 118 | - '&7游戏前期一定要多造矿场,尽量把所有矿场都升到满级,满级矿工挖一个绿宝石矿,会掉落&a30个绿宝石!' 119 | - '&7防空塔的攻击半径是50格距离,3级几乎可以瞬间秒杀在天上的敌人哦~' 120 | - '&7桥可以在很多地方建造,小心敌人从四面八方过来拆你的基地哦!' 121 | - '&a小提示:蹲下对着战士按右键,可以让战士跟着你走哦~' 122 | - '&f防空塔,兵营,修复塔迎来了史诗级的加强~' 123 | - '&f可以敲自己家的建筑给建筑回血!~' 124 | - '&c请注意:新版本移除了积分判定胜负的条件,改为基地血量最多的队伍获得胜利!!!积分会在正式版本当中结算给玩家用于购买皮肤等用途,请注意调整战略!~' -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: COIRealm 2 | main: com.mcylm.coi.realm.Entry 3 | description: A RTS MINI GAME PLUGIN 4 | api-version: 1.19 5 | version: 1.0 6 | author: Mikesam 7 | website: https://www.mcylm.com 8 | depend: [helper,Citizens] 9 | softdepend: 10 | - Multiverse-Core 11 | - LibsDisguises 12 | - Hermes 13 | commands: 14 | structure: 15 | description: save building structure 16 | usage: / save fileName 17 | cdebug: 18 | all: 19 | cvein: 20 | permission: coi.realm.vein 21 | cspawnpoint: 22 | permission: coi.realm.spawnpoint 23 | aliases: 24 | - csp 25 | --------------------------------------------------------------------------------