├── lib └── NsGameBase_FakeLib.jar ├── pic ├── en-US │ ├── screenshot_01.jpg │ ├── screenshot_02.jpg │ └── screenshot_03.jpg └── zh-CN │ ├── screenshot_01.png │ ├── screenshot_02.png │ └── screenshot_03.png ├── src └── main │ ├── resources │ ├── Resources │ │ ├── Flag │ │ │ ├── RedFlag.png │ │ │ ├── BlueFlag.png │ │ │ ├── WhiteFlag.png │ │ │ ├── LongFlagNoHead.json │ │ │ ├── FlagHead.json │ │ │ ├── FlagStand.json │ │ │ ├── Flag.json │ │ │ └── LongFlag.json │ │ └── CrossbowTower │ │ │ └── CrossbowTower.png │ ├── Supply │ │ └── DefaultSupply │ │ │ ├── pages │ │ │ └── Main.yml │ │ │ └── items │ │ │ └── DemoGun.yml │ ├── ItemKillMessage.yml │ ├── Items │ │ └── Weapon │ │ │ ├── Melee │ │ │ └── DemoMelee.yml │ │ │ ├── Projectile │ │ │ ├── DemoFlashbang.yml │ │ │ └── DemoGrenade.yml │ │ │ └── Gun │ │ │ └── DemoGun.yml │ ├── plugin.yml │ ├── RankingConfig.yml │ └── config.yml │ └── java │ └── cn │ └── lanink │ └── gunwar │ ├── gui │ └── GuiType.java │ ├── room │ ├── base │ │ ├── ITimeTask.java │ │ ├── Team.java │ │ ├── BaseRoundModeRoom.java │ │ ├── PlayerGameData.java │ │ ├── IntegralConfig.java │ │ └── BaseRespawnModeRoom.java │ ├── classic │ │ └── ClassicModeRoom.java │ ├── team │ │ └── TeamModeRoom.java │ └── freeforall │ │ └── FreeForAllModeRoom.java │ ├── utils │ ├── nsgb │ │ ├── GunWarDataGamePlayerPojo.java │ │ └── GunWarDataGamePlayerPojoUtils.java │ ├── exception │ │ ├── item │ │ │ ├── ItemException.java │ │ │ └── weapon │ │ │ │ ├── ProjectileWeaponLoadException.java │ │ │ │ └── WeaponException.java │ │ └── supply │ │ │ └── SupplyConfigLoadException.java │ ├── gamerecord │ │ ├── RecordType.java │ │ ├── GameRecord.java │ │ └── RankingManager.java │ ├── FlagSkinType.java │ ├── ui │ │ └── advanced │ │ │ ├── AdvancedPageLinkItem.java │ │ │ └── AdvancedBuyItem.java │ ├── rsnpc │ │ └── RsNpcVariableV2.java │ ├── update │ │ └── ConfigUpdateUtils.java │ └── ItemKillMessageUtils.java │ ├── event │ ├── GunWarRoomEvent.java │ ├── GunWarRoomPlayerEvent.java │ ├── GunWarRoomStartEvent.java │ ├── GunWarRoomAssignTeamEvent.java │ ├── GunWarRoomRoundStartEvent.java │ ├── GunWarPlayerRespawnEvent.java │ ├── GunWarPlayerCorpseSpawnEvent.java │ ├── GunWarRoomPlayerJoinEvent.java │ ├── GunWarRoomPlayerQuitEvent.java │ ├── GunWarPlayerDeathEvent.java │ ├── GunWarRoomRoundEndEvent.java │ ├── GunWarPlayerDamageEvent.java │ ├── GunWarSwapTeamEvent.java │ └── GunWarRoomEndEvent.java │ ├── entity │ ├── bullet │ │ ├── IBullet.java │ │ ├── BulletSnowBall.java │ │ └── BulletArrow.java │ ├── tower │ │ ├── TowerDefinition.java │ │ ├── EntityCrossbowTower.java │ │ └── EntityBaseTower.java │ ├── EntityText.java │ ├── EntityPlayerCorpse.java │ ├── flag │ │ ├── EntityFlagStand.java │ │ ├── EntityFlag.java │ │ └── EntityLongFlag.java │ ├── EntityGunWarBombBlock.java │ └── EntityGunWarBomb.java │ ├── tasks │ ├── game │ │ ├── TimeTask.java │ │ ├── ctf │ │ │ ├── FlagPickupCheckTask.java │ │ │ └── FlagTask.java │ │ ├── ScoreBoardTask.java │ │ ├── conquest │ │ │ ├── FlagSpawnCheckTask.java │ │ │ └── AsyncFlagRadiusCheckTask.java │ │ ├── ShowHealthTask.java │ │ └── blasting │ │ │ ├── DemolitionBombTask.java │ │ │ └── PlantBombTask.java │ ├── GunReloadTask.java │ ├── WaitTask.java │ └── VictoryTask.java │ ├── listener │ ├── defaults │ │ ├── nkmot │ │ │ └── NKMOTRoomLevelProtection.java │ │ ├── nkpm1e │ │ │ └── PM1ERoomLevelProtection.java │ │ ├── DebugMessageListener.java │ │ ├── DefaultChatListener.java │ │ └── PlayerJoinAndQuit.java │ └── capturetheflag │ │ └── CTFDamageListener.java │ ├── item │ ├── weapon │ │ ├── MeleeWeapon.java │ │ ├── ProjectileWeapon.java │ │ ├── BaseWeapon.java │ │ └── GunWeapon.java │ └── base │ │ └── BaseItem.java │ ├── command │ ├── usersub │ │ ├── RecordCommand.java │ │ ├── ListCommand.java │ │ ├── QuitCommand.java │ │ └── JoinCommand.java │ ├── adminsub │ │ ├── ReloadCommand.java │ │ ├── UnloadCommand.java │ │ ├── AddWeapon.java │ │ ├── CreateRank.java │ │ ├── StopRoom.java │ │ ├── StartRoom.java │ │ ├── SetRoom.java │ │ └── CreateRoom.java │ ├── UserCommand.java │ ├── AdminCommand.java │ └── base │ │ ├── BaseSubCommand.java │ │ └── BaseCommand.java │ └── supplier │ ├── pages │ └── LinkItem.java │ ├── items │ └── SupplyItemConfig.java │ ├── SupplyConfigManager.java │ └── SupplyConfig.java ├── .github └── workflows │ └── maven.yml ├── README(zh-CN).md └── README.md /lib/NsGameBase_FakeLib.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MemoriesOfTime/GunWar/HEAD/lib/NsGameBase_FakeLib.jar -------------------------------------------------------------------------------- /pic/en-US/screenshot_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MemoriesOfTime/GunWar/HEAD/pic/en-US/screenshot_01.jpg -------------------------------------------------------------------------------- /pic/en-US/screenshot_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MemoriesOfTime/GunWar/HEAD/pic/en-US/screenshot_02.jpg -------------------------------------------------------------------------------- /pic/en-US/screenshot_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MemoriesOfTime/GunWar/HEAD/pic/en-US/screenshot_03.jpg -------------------------------------------------------------------------------- /pic/zh-CN/screenshot_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MemoriesOfTime/GunWar/HEAD/pic/zh-CN/screenshot_01.png -------------------------------------------------------------------------------- /pic/zh-CN/screenshot_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MemoriesOfTime/GunWar/HEAD/pic/zh-CN/screenshot_02.png -------------------------------------------------------------------------------- /pic/zh-CN/screenshot_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MemoriesOfTime/GunWar/HEAD/pic/zh-CN/screenshot_03.png -------------------------------------------------------------------------------- /src/main/resources/Resources/Flag/RedFlag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MemoriesOfTime/GunWar/HEAD/src/main/resources/Resources/Flag/RedFlag.png -------------------------------------------------------------------------------- /src/main/resources/Resources/Flag/BlueFlag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MemoriesOfTime/GunWar/HEAD/src/main/resources/Resources/Flag/BlueFlag.png -------------------------------------------------------------------------------- /src/main/resources/Resources/Flag/WhiteFlag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MemoriesOfTime/GunWar/HEAD/src/main/resources/Resources/Flag/WhiteFlag.png -------------------------------------------------------------------------------- /src/main/resources/Supply/DefaultSupply/pages/Main.yml: -------------------------------------------------------------------------------- 1 | # 快速购买 默认页面 2 | --- 3 | title: 商店 4 | default: true 5 | linkItems: {} 6 | items: 7 | - DemoGun 8 | -------------------------------------------------------------------------------- /src/main/resources/Resources/CrossbowTower/CrossbowTower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MemoriesOfTime/GunWar/HEAD/src/main/resources/Resources/CrossbowTower/CrossbowTower.png -------------------------------------------------------------------------------- /src/main/resources/Supply/DefaultSupply/items/DemoGun.yml: -------------------------------------------------------------------------------- 1 | title: DemoGun 2 | subTitle: "购买需要200积分" 3 | items: 4 | - "35:0&1@item" 5 | - "DemoGun&1@weapon_gun" 6 | needIntegral: 200 7 | pos: 0 -------------------------------------------------------------------------------- /src/main/resources/ItemKillMessage.yml: -------------------------------------------------------------------------------- 1 | #原版/自定义物品的击杀提示信息 2 | #格式: "物品ID(数字ID或字符串ID)": "击杀信息" 3 | "280:0": "%damager% 用棍子敲死了 %player%" 4 | "gun:m249": "%player% 被 %damager% 用机枪扫死了!" 5 | "gun:m3": "%damager% 一枪把 %player% 给打成了筛子!" 6 | "gun:barrett": "%damager% 成功狙掉了 %player%" -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/gui/GuiType.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.gui; 2 | 3 | public enum GuiType { 4 | 5 | ADMIN_ITEM_ADD_WEAPON_MELEE, 6 | ADMIN_ITEM_ADD_WEAPON_PROJECTILE, 7 | ADMIN_ITEM_ADD_WEAPON_GUN, 8 | 9 | ROOM_JOIN_OK, 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/room/base/ITimeTask.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.room.base; 2 | 3 | import cn.lanink.gamecore.room.IRoomStatus; 4 | 5 | /** 6 | * @author lt_name 7 | */ 8 | public interface ITimeTask extends IRoomStatus { 9 | 10 | void timeTask(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/nsgb/GunWarDataGamePlayerPojo.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils.nsgb; 2 | 3 | import cn.nsgamebase.entity.pojo.AbstractDataGamePlayerPojo; 4 | 5 | /** 6 | * @author LT_Name 7 | */ 8 | public class GunWarDataGamePlayerPojo extends AbstractDataGamePlayerPojo { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/resources/Items/Weapon/Melee/DemoMelee.yml: -------------------------------------------------------------------------------- 1 | showName: "剑" 2 | id: "272:0" 3 | lore: |- 4 | 伤害:1-2 5 | 攻击冷却:1.5秒 6 | damage: "1-2" 7 | effect: [] 8 | attackCooldown: 30 #tick 9 | knockBack: 0.3 10 | infiniteDurability: true 11 | enchantment: 12 | - id: 17 13 | level: 1 14 | killMessage: "%damager% --[+==》 %player%" -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/event/GunWarRoomEvent.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.event; 2 | 3 | import cn.lanink.gunwar.room.base.BaseRoom; 4 | import cn.nukkit.event.Event; 5 | 6 | public abstract class GunWarRoomEvent extends Event { 7 | 8 | protected BaseRoom room; 9 | 10 | public BaseRoom getRoom() { 11 | return this.room; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/entity/bullet/IBullet.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.entity.bullet; 2 | 3 | import cn.nukkit.level.ParticleEffect; 4 | 5 | /** 6 | * @author lt_name 7 | */ 8 | public interface IBullet { 9 | 10 | void setGravity(float gravity); 11 | 12 | float getGravity(); 13 | 14 | void setParticleEffect(ParticleEffect particleEffect); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/exception/item/ItemException.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils.exception.item; 2 | 3 | /** 4 | * @author lt_name 5 | */ 6 | public class ItemException extends Exception { 7 | 8 | public ItemException() { 9 | super(); 10 | } 11 | 12 | public ItemException(String message) { 13 | super(message); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/exception/supply/SupplyConfigLoadException.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils.exception.supply; 2 | 3 | /** 4 | * @author LT_Name 5 | */ 6 | public class SupplyConfigLoadException extends Exception { 7 | 8 | public SupplyConfigLoadException() { 9 | super(); 10 | } 11 | 12 | public SupplyConfigLoadException(String message) { 13 | super(message); 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /src/main/resources/Items/Weapon/Projectile/DemoFlashbang.yml: -------------------------------------------------------------------------------- 1 | showName: "闪光弹" 2 | id: "344:0" 3 | lore: |- 4 | 致盲敌人(失明药水效果) 5 | damage: "0" #根据距离浮动 6 | effect: 7 | - id: 15 8 | amplifier: 1 #效果等级 9 | duration: 100 #tick 10 | visible: true #可见 11 | particle: "SpellParticle@Vector3:pos&int:255&int:255&int:255" 12 | attackCooldown: 0 #tick 13 | range: 5 #如果设为0 则只有在击中时有效 14 | enchantment: [] 15 | killMessage: "%damager% ☼ %player%" -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/event/GunWarRoomPlayerEvent.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.event; 2 | 3 | import cn.lanink.gunwar.room.base.BaseRoom; 4 | import cn.nukkit.event.player.PlayerEvent; 5 | 6 | /** 7 | * @author LT_Name 8 | */ 9 | public abstract class GunWarRoomPlayerEvent extends PlayerEvent { 10 | 11 | protected BaseRoom room; 12 | 13 | public BaseRoom getRoom() { 14 | return this.room; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/exception/item/weapon/ProjectileWeaponLoadException.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils.exception.item.weapon; 2 | 3 | /** 4 | * @author lt_name 5 | */ 6 | public class ProjectileWeaponLoadException extends WeaponException { 7 | 8 | public ProjectileWeaponLoadException() { 9 | super(); 10 | } 11 | 12 | public ProjectileWeaponLoadException(String message) { 13 | super(message); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/Items/Weapon/Gun/DemoGun.yml: -------------------------------------------------------------------------------- 1 | showName: "手枪" 2 | id: "290:0" 3 | lore: |- 4 | 伤害:3-5 5 | 弹夹:15发 6 | 换弹时间:2.5秒 7 | damage: "3-5" 8 | effect: [] 9 | attackCooldown: 10 #tick 10 | maxMagazine: 15 11 | reloadTime: 50 #tick 12 | reloadInterrupted: false #换弹是否允许中断 13 | gravity: 0.005 #子弹重力(普通雪球为0.03) 14 | motionMultiply: 1.5 #移动倍速(普通雪球为1.5) 15 | enchantment: 16 | - id: 17 17 | level: 1 18 | particleEffect: "" 19 | killMessage: "%damager% ︻┳═一 %player%" -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: GunWar 2 | main: cn.lanink.gunwar.GunWar 3 | version: "1.7.3-NKMOT" 4 | api: ["Nukkit-MOT"] 5 | load: POSTWORLD 6 | author: "LT_Name" 7 | website: "https://www.lanink.cn" 8 | depend: 9 | - "MemoriesOfTime-GameCore" 10 | softdepend: 11 | - "NsGameBase" 12 | 13 | permissions: 14 | GunWar.command.user: 15 | description: "GunWar 命令" 16 | default: true 17 | GunWar.command.admin: 18 | description: "GunWar 管理命令" 19 | default: op -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/exception/item/weapon/WeaponException.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils.exception.item.weapon; 2 | 3 | import cn.lanink.gunwar.utils.exception.item.ItemException; 4 | 5 | /** 6 | * @author lt_name 7 | */ 8 | public class WeaponException extends ItemException { 9 | 10 | public WeaponException() { 11 | super(); 12 | } 13 | 14 | public WeaponException(String message) { 15 | super(message); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/RankingConfig.yml: -------------------------------------------------------------------------------- 1 | #排行榜格式 2 | RankingFormat: 3 | Top: "§b<<§a[§e%name%§a]§b>>" 4 | Line: "§bTop[%ranking%] §cName: §a%player% §cVictory: §b%score%" 5 | LineSelf: "§bTop[%ranking%] §cName: §e%player%(me) §cVictory: §b%score%" 6 | Bottom: "§b<<§a[§e%name%§a]§b>>" 7 | ShowLine: 8 | '3': 15 9 | '5': 10 10 | '15': 5 11 | '20': 3 12 | #pos: 13 | # - name: "测试排行榜" 14 | # type: kills 15 | # x: 0.0 16 | # y: 0.0 17 | # z: 0.0 18 | # level: "world" 19 | pos: [] -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/event/GunWarRoomStartEvent.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.event; 2 | 3 | import cn.lanink.gunwar.room.base.BaseRoom; 4 | import cn.nukkit.event.HandlerList; 5 | 6 | public class GunWarRoomStartEvent extends GunWarRoomEvent { 7 | 8 | private static final HandlerList handlers = new HandlerList(); 9 | 10 | public static HandlerList getHandlers() { 11 | return handlers; 12 | } 13 | 14 | public GunWarRoomStartEvent(BaseRoom room) { 15 | this.room = room; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/Items/Weapon/Projectile/DemoGrenade.yml: -------------------------------------------------------------------------------- 1 | showName: "手榴弹" 2 | id: "344:0" 3 | lore: |- 4 | 伤害:2-10(根据距离浮动) 5 | damage: "2-10" #根据距离浮动 6 | effect: 7 | - id: 9 8 | amplifier: 1 #效果等级 9 | duration: 40 #tick 10 | visible: true #可见 11 | color: #粒子颜色 不写即为默认颜色 12 | r: 84 13 | g: 255 14 | b: 159 15 | particle: "HugeExplodeSeedParticle@Vector3:pos" 16 | attackCooldown: 0 #tick 17 | range: 5 #如果设为0 则只有在击中时有效 18 | enchantment: 19 | - id: 17 20 | level: 1 21 | killMessage: "%damager% ☼ %player%" -------------------------------------------------------------------------------- /src/main/resources/Resources/Flag/LongFlagNoHead.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.10.0", 3 | "geometry.LongFlagNoHead": { 4 | "texturewidth": 64, 5 | "textureheight": 64, 6 | "visible_bounds_width": 2, 7 | "visible_bounds_height": 5, 8 | "visible_bounds_offset": [0, 1.5, 0], 9 | "bones": [ 10 | { 11 | "name": "body", 12 | "pivot": [0, 0, 0], 13 | "cubes": [ 14 | {"origin": [-1, 0, -1], "size": [2, 28, 2], "uv": [55, 34]}, 15 | {"origin": [-1, 28, -1], "size": [2, 20, 2], "uv": [55, 34]} 16 | ] 17 | } 18 | ] 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/resources/Resources/Flag/FlagHead.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.10.0", 3 | "geometry.FlagHead": { 4 | "texturewidth": 64, 5 | "textureheight": 64, 6 | "visible_bounds_width": 2, 7 | "visible_bounds_height": 5, 8 | "visible_bounds_offset": [0, 1.5, 0], 9 | "bones": [ 10 | { 11 | "name": "body", 12 | "pivot": [0, 0, 0], 13 | "cubes": [ 14 | {"origin": [4, 0, 0], "size": [2, 5, 2], "uv": [0, 6]}, 15 | {"origin": [6, 0, 1], "size": [3, 5, 2], "uv": [0, 0]}, 16 | {"origin": [1, 0, -1], "size": [3, 5, 2], "uv": [0, 0]} 17 | ] 18 | } 19 | ] 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/entity/tower/TowerDefinition.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.entity.tower; 2 | 3 | import cn.nukkit.entity.data.Skin; 4 | import lombok.Data; 5 | 6 | /** 7 | * @author LT_Name 8 | */ 9 | @Data 10 | public class TowerDefinition { 11 | 12 | public static TowerDefinition DEFAULT = new TowerDefinition(); 13 | 14 | private String name; 15 | private Skin skin; 16 | private int maxHealth; //血量 17 | private int attackDamage; //伤害 18 | private int attackSpeed; //攻速 19 | private int attackMaxRange; //最大范围 20 | private int attackMinRange; //最小范围 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/event/GunWarRoomAssignTeamEvent.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.event; 2 | 3 | import cn.lanink.gunwar.room.base.BaseRoom; 4 | import cn.nukkit.event.Cancellable; 5 | import cn.nukkit.event.HandlerList; 6 | 7 | public class GunWarRoomAssignTeamEvent extends GunWarRoomEvent implements Cancellable { 8 | 9 | private static final HandlerList handlers = new HandlerList(); 10 | 11 | public static HandlerList getHandlers() { 12 | return handlers; 13 | } 14 | 15 | public GunWarRoomAssignTeamEvent(BaseRoom room) { 16 | this.room = room; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/event/GunWarRoomRoundStartEvent.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.event; 2 | 3 | import cn.lanink.gunwar.room.base.BaseRoom; 4 | import cn.nukkit.event.Cancellable; 5 | import cn.nukkit.event.HandlerList; 6 | 7 | public class GunWarRoomRoundStartEvent extends GunWarRoomEvent implements Cancellable { 8 | 9 | private static final HandlerList handlers = new HandlerList(); 10 | 11 | public static HandlerList getHandlers() { 12 | return handlers; 13 | } 14 | 15 | public GunWarRoomRoundStartEvent(BaseRoom room) { 16 | this.room = room; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/Resources/Flag/FlagStand.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.10.0", 3 | "geometry.FlagStand": { 4 | "texturewidth": 64, 5 | "textureheight": 64, 6 | "visible_bounds_width": 2, 7 | "visible_bounds_height": 2, 8 | "visible_bounds_offset": [0, 0, 0], 9 | "bones": [ 10 | { 11 | "name": "body", 12 | "pivot": [1, 7, 0], 13 | "cubes": [ 14 | {"origin": [-8, 0, -8], "size": [16, 3, 16], "uv": [0, 0]}, 15 | {"origin": [-6, 3, -6], "size": [12, 2, 12], "uv": [0, 19]}, 16 | {"origin": [-4, 5, -4], "size": [8, 2, 8], "uv": [0, 33]} 17 | ] 18 | } 19 | ] 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/room/base/Team.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.room.base; 2 | 3 | import cn.lanink.gunwar.utils.Tools; 4 | 5 | /** 6 | * @author LT_Name 7 | */ 8 | public enum Team { 9 | 10 | /** 11 | * 未分配队伍 12 | */ 13 | NULL, 14 | 15 | /** 16 | * 红队 17 | */ 18 | RED, 19 | 20 | /** 21 | * 红队(已死亡) 22 | */ 23 | RED_DEATH, 24 | 25 | /** 26 | * 蓝队 27 | */ 28 | BLUE, 29 | 30 | /** 31 | * 蓝队(已死亡) 32 | */ 33 | BLUE_DEATH; 34 | 35 | public String getShowName() { 36 | return Tools.getShowTeamName(this); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/entity/EntityText.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.entity; 2 | 3 | import cn.nukkit.entity.Entity; 4 | import cn.nukkit.level.Position; 5 | 6 | /** 7 | * @author lt_name 8 | */ 9 | public class EntityText extends Entity { 10 | 11 | @Override 12 | public int getNetworkId() { 13 | return 64; 14 | } 15 | 16 | public EntityText(Position position, String nameTag) { 17 | super(position.getChunk(), Entity.getDefaultNBT(position)); 18 | this.setNameTagVisible(true); 19 | this.setNameTagAlwaysVisible(true); 20 | this.setNameTag(nameTag); 21 | this.setImmobile(true); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/event/GunWarPlayerRespawnEvent.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.event; 2 | 3 | import cn.lanink.gunwar.room.base.BaseRoom; 4 | import cn.nukkit.Player; 5 | import cn.nukkit.event.Cancellable; 6 | import cn.nukkit.event.HandlerList; 7 | 8 | public class GunWarPlayerRespawnEvent extends GunWarRoomPlayerEvent implements Cancellable { 9 | 10 | private static final HandlerList handlers = new HandlerList(); 11 | 12 | public GunWarPlayerRespawnEvent(BaseRoom room, Player player) { 13 | this.room = room; 14 | this.player = player; 15 | } 16 | 17 | public static HandlerList getHandlers() { 18 | return handlers; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/event/GunWarPlayerCorpseSpawnEvent.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.event; 2 | 3 | import cn.lanink.gunwar.room.base.BaseRoom; 4 | import cn.nukkit.Player; 5 | import cn.nukkit.event.Cancellable; 6 | import cn.nukkit.event.HandlerList; 7 | 8 | public class GunWarPlayerCorpseSpawnEvent extends GunWarRoomPlayerEvent implements Cancellable { 9 | 10 | private static final HandlerList handlers = new HandlerList(); 11 | 12 | public static HandlerList getHandlers() { 13 | return handlers; 14 | } 15 | 16 | public GunWarPlayerCorpseSpawnEvent(BaseRoom room, Player player) { 17 | this.room = room; 18 | this.player = player; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/entity/EntityPlayerCorpse.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.entity; 2 | 3 | import cn.lanink.gunwar.room.base.Team; 4 | import cn.lanink.gunwar.utils.Tools; 5 | import cn.nukkit.level.format.FullChunk; 6 | import cn.nukkit.nbt.tag.CompoundTag; 7 | 8 | /** 9 | * 玩家尸体 10 | * @author 若水 11 | */ 12 | public class EntityPlayerCorpse extends cn.lanink.gamecore.entity.EntityPlayerCorpse { 13 | 14 | public EntityPlayerCorpse(FullChunk chunk, CompoundTag nbt, Team team) { 15 | super(chunk, nbt); 16 | this.setNameTagVisible(false); 17 | this.setNameTagAlwaysVisible(false); 18 | this.inventory.setArmorContents(Tools.getArmors(team)); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/event/GunWarRoomPlayerJoinEvent.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.event; 2 | 3 | import cn.lanink.gunwar.room.base.BaseRoom; 4 | import cn.nukkit.Player; 5 | import cn.nukkit.event.HandlerList; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * @author LT_Name 10 | */ 11 | public class GunWarRoomPlayerJoinEvent extends GunWarRoomPlayerEvent { 12 | 13 | private static final HandlerList handlers = new HandlerList(); 14 | 15 | public static HandlerList getHandlers() { 16 | return handlers; 17 | } 18 | 19 | public GunWarRoomPlayerJoinEvent(@NotNull BaseRoom room, @NotNull Player player) { 20 | this.room = room; 21 | this.player = player; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/event/GunWarRoomPlayerQuitEvent.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.event; 2 | 3 | import cn.lanink.gunwar.room.base.BaseRoom; 4 | import cn.nukkit.Player; 5 | import cn.nukkit.event.HandlerList; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * @author LT_Name 10 | */ 11 | public class GunWarRoomPlayerQuitEvent extends GunWarRoomPlayerEvent { 12 | 13 | private static final HandlerList handlers = new HandlerList(); 14 | 15 | public static HandlerList getHandlers() { 16 | return handlers; 17 | } 18 | 19 | public GunWarRoomPlayerQuitEvent(@NotNull BaseRoom room, @NotNull Player player) { 20 | this.room = room; 21 | this.player = player; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/gamerecord/RecordType.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils.gamerecord; 2 | 3 | /** 4 | * @author lt_name 5 | */ 6 | public enum RecordType { 7 | KILLS("kills"), 8 | DEATHS("deaths"), 9 | VICTORY("victory"), 10 | DEFEAT("defeat"); 11 | 12 | private final String name; 13 | 14 | RecordType(String name) { 15 | this.name = name; 16 | } 17 | 18 | public String getName() { 19 | return this.name; 20 | } 21 | 22 | public static RecordType of(String name) { 23 | for (RecordType type : values()) { 24 | if (type.name.equalsIgnoreCase(name)) { //忽略大小写 25 | return type; 26 | } 27 | } 28 | return null; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/Resources/Flag/Flag.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.10.0", 3 | "geometry.flag2": { 4 | "texturewidth": 64, 5 | "textureheight": 64, 6 | "visible_bounds_width": 2, 7 | "visible_bounds_height": 4, 8 | "visible_bounds_offset": [0, 1, 0], 9 | "bones": [ 10 | { 11 | "name": "head", 12 | "pivot": [0, 0, 0], 13 | "cubes": [ 14 | {"origin": [4, 23, 0], "size": [2, 5, 2], "uv": [0, 6]}, 15 | {"origin": [6, 23, 1], "size": [3, 5, 2], "uv": [0, 0]}, 16 | {"origin": [1, 23, -1], "size": [3, 5, 2], "uv": [0, 0]} 17 | ] 18 | }, 19 | { 20 | "name": "body", 21 | "pivot": [0, 0, 0], 22 | "cubes": [ 23 | {"origin": [-1, 0, -1], "size": [2, 28, 2], "uv": [55, 34]} 24 | ] 25 | } 26 | ] 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/tasks/game/TimeTask.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.tasks.game; 2 | 3 | import cn.lanink.gamecore.room.IRoomStatus; 4 | import cn.lanink.gunwar.GunWar; 5 | import cn.lanink.gunwar.room.base.ITimeTask; 6 | import cn.nukkit.scheduler.PluginTask; 7 | 8 | /** 9 | * 游戏时间计算 10 | */ 11 | public class TimeTask extends PluginTask { 12 | 13 | private final ITimeTask task; 14 | 15 | public TimeTask(GunWar owner, ITimeTask task) { 16 | super(owner); 17 | this.task = task; 18 | } 19 | 20 | @Override 21 | public void onRun(int i) { 22 | if (this.task.getStatus() != IRoomStatus.ROOM_STATUS_GAME) { 23 | this.cancel(); 24 | return; 25 | } 26 | this.task.timeTask(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/entity/flag/EntityFlagStand.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.entity.flag; 2 | 3 | import cn.nukkit.entity.EntityHuman; 4 | import cn.nukkit.level.format.FullChunk; 5 | import cn.nukkit.nbt.tag.CompoundTag; 6 | 7 | /** 8 | * @author lt_name 9 | */ 10 | public class EntityFlagStand extends EntityHuman { 11 | 12 | public EntityFlagStand(FullChunk chunk, CompoundTag nbt) { 13 | super(chunk, nbt); 14 | this.setNameTagVisible(false); 15 | this.setNameTagAlwaysVisible(false); 16 | } 17 | 18 | @Override 19 | public float getHeight() { 20 | return 0.5F; 21 | } 22 | 23 | @Override 24 | public float getLength() { 25 | return 1; 26 | } 27 | 28 | @Override 29 | public float getWidth() { 30 | return 1; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/listener/defaults/nkmot/NKMOTRoomLevelProtection.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.listener.defaults.nkmot; 2 | 3 | import cn.lanink.gunwar.listener.defaults.RoomLevelProtection; 4 | import cn.nukkit.event.EventHandler; 5 | import cn.nukkit.event.block.ItemFrameUseEvent; 6 | import cn.nukkit.level.Level; 7 | 8 | /** 9 | * @author LT_Name 10 | */ 11 | public class NKMOTRoomLevelProtection extends RoomLevelProtection { 12 | 13 | /** 14 | * 物品展示框操作事件 15 | * @param event 事件 16 | */ 17 | @EventHandler 18 | public void onItemFrameUse(ItemFrameUseEvent event) { 19 | Level level = event.getItemFrame().getLevel(); 20 | if (level != null && this.getListenerRooms().containsKey(level.getFolderName())) { 21 | event.setCancelled(); 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/room/base/BaseRoundModeRoom.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.room.base; 2 | 3 | import cn.lanink.gamecore.utils.exception.RoomLoadException; 4 | import cn.nukkit.level.Level; 5 | import cn.nukkit.utils.Config; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * 多回合不可重生房间类型 10 | * 11 | * @author LT_Name 12 | */ 13 | public abstract class BaseRoundModeRoom extends BaseRoom { 14 | 15 | /** 16 | * 初始化 17 | * 18 | * @param level 游戏世界 19 | * @param config 配置文件 20 | */ 21 | public BaseRoundModeRoom(@NotNull Level level, @NotNull Config config) throws RoomLoadException { 22 | super(level, config); 23 | } 24 | 25 | public void setRoundIsEnd(boolean roundEnd) { 26 | this.setRoundEnd(roundEnd); 27 | } 28 | 29 | //TODO 将一些多回合相关操作移到这个类! 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/Resources/Flag/LongFlag.json: -------------------------------------------------------------------------------- 1 | { 2 | "format_version": "1.10.0", 3 | "geometry.flag2": { 4 | "texturewidth": 64, 5 | "textureheight": 64, 6 | "visible_bounds_width": 2, 7 | "visible_bounds_height": 5, 8 | "visible_bounds_offset": [0, 1.5, 0], 9 | "bones": [ 10 | { 11 | "name": "head", 12 | "pivot": [0, 0, 0], 13 | "cubes": [ 14 | {"origin": [4, 43, 0], "size": [2, 5, 2], "uv": [0, 6]}, 15 | {"origin": [6, 43, 1], "size": [3, 5, 2], "uv": [0, 0]}, 16 | {"origin": [1, 43, -1], "size": [3, 5, 2], "uv": [0, 0]} 17 | ] 18 | }, 19 | { 20 | "name": "body", 21 | "pivot": [0, 0, 0], 22 | "cubes": [ 23 | {"origin": [-1, 0, -1], "size": [2, 28, 2], "uv": [55, 34]}, 24 | {"origin": [-1, 28, -1], "size": [2, 20, 2], "uv": [55, 34]} 25 | ] 26 | } 27 | ] 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/listener/defaults/nkpm1e/PM1ERoomLevelProtection.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.listener.defaults.nkpm1e; 2 | 3 | import cn.lanink.gunwar.listener.defaults.RoomLevelProtection; 4 | import cn.nukkit.event.EventHandler; 5 | import cn.nukkit.event.block.ItemFrameDropItemEvent; 6 | import cn.nukkit.level.Level; 7 | 8 | /** 9 | * @author LT_Name 10 | */ 11 | public class PM1ERoomLevelProtection extends RoomLevelProtection { 12 | 13 | /** 14 | * 物品展示框丢出事件 15 | * @param event 事件 16 | */ 17 | @EventHandler 18 | public void onFrameDropItem(ItemFrameDropItemEvent event) { 19 | Level level = event.getItemFrame() == null ? null : event.getItemFrame().getLevel(); 20 | if (level != null && this.getListenerRooms().containsKey(level.getFolderName())) { 21 | event.setCancelled(); 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/FlagSkinType.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils; 2 | 3 | /** 4 | * @author LT_Name 5 | */ 6 | public enum FlagSkinType { 7 | 8 | /** 9 | * 白色小旗帜 10 | */ 11 | FLAG_WHITE, 12 | 13 | /** 14 | * 红色小旗帜 15 | */ 16 | FLAG_RED, 17 | 18 | /** 19 | * 蓝色小旗帜 20 | */ 21 | FLAG_BLUE, 22 | 23 | /** 24 | * 白色旗帜底座 25 | */ 26 | FLAG_STAND_WHITE, 27 | 28 | /** 29 | * 红色旗帜底座 30 | */ 31 | FLAG_STAND_RED, 32 | 33 | /** 34 | * 蓝色旗帜底座 35 | */ 36 | FLAG_STAND_BLUE, 37 | 38 | /** 39 | * 长旗杆 40 | */ 41 | LONG_FLAGPOLE, 42 | 43 | /** 44 | * 白色旗帜头 45 | */ 46 | FLAG_HEAD_WHITE, 47 | 48 | /** 49 | * 红色旗帜头 50 | */ 51 | FLAG_HEAD_RED, 52 | 53 | /** 54 | * 蓝色旗帜头 55 | */ 56 | FLAG_HEAD_BLUE 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: 4 | push: 5 | branches: [ master, NKMOT ] 6 | pull_request: 7 | branches: [ master, NKMOT ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Set up JDK 1.8 16 | uses: actions/setup-java@v4 17 | with: 18 | java-version: 8 19 | distribution: 'zulu' 20 | - name: Cache Maven packages 21 | uses: actions/cache@v4 22 | with: 23 | path: ~/.m2 24 | key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} 25 | restore-keys: ${{ runner.os }}-m2 26 | - name: Build projects 27 | run: mvn -B package --file pom.xml 28 | - run: mkdir staging && cp target/*.jar staging 29 | - uses: actions/upload-artifact@v4 30 | with: 31 | name: GunWar-SNAPSHOT 32 | path: staging 33 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/event/GunWarPlayerDeathEvent.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.event; 2 | 3 | import cn.lanink.gunwar.room.base.BaseRoom; 4 | import cn.nukkit.Player; 5 | import cn.nukkit.entity.Entity; 6 | import cn.nukkit.event.Cancellable; 7 | import cn.nukkit.event.HandlerList; 8 | 9 | public class GunWarPlayerDeathEvent extends GunWarRoomPlayerEvent implements Cancellable { 10 | 11 | private static final HandlerList handlers = new HandlerList(); 12 | private Entity damager; 13 | 14 | public static HandlerList getHandlers() { 15 | return handlers; 16 | } 17 | 18 | public GunWarPlayerDeathEvent(BaseRoom room, Player player, Entity damager) { 19 | this.room = room; 20 | this.player = player; 21 | this.damager = damager; 22 | } 23 | 24 | public Entity getDamagePlayer() { 25 | return this.damager; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/event/GunWarRoomRoundEndEvent.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.event; 2 | 3 | import cn.lanink.gunwar.room.base.BaseRoom; 4 | import cn.lanink.gunwar.room.base.Team; 5 | import cn.nukkit.event.Cancellable; 6 | import cn.nukkit.event.HandlerList; 7 | 8 | public class GunWarRoomRoundEndEvent extends GunWarRoomEvent implements Cancellable { 9 | 10 | private static final HandlerList handlers = new HandlerList(); 11 | private Team victoryTeam; 12 | 13 | public static HandlerList getHandlers() { 14 | return handlers; 15 | } 16 | 17 | public GunWarRoomRoundEndEvent(BaseRoom room, Team victory) { 18 | this.room = room; 19 | this.victoryTeam = victory; 20 | } 21 | 22 | public void setVictoryTeam(Team victoryTeam) { 23 | this.victoryTeam = victoryTeam; 24 | } 25 | 26 | public Team getVictoryTeam() { 27 | return this.victoryTeam; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/item/weapon/MeleeWeapon.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.item.weapon; 2 | 3 | import cn.lanink.gunwar.item.ItemManage; 4 | import cn.nukkit.nbt.tag.CompoundTag; 5 | import cn.nukkit.utils.Config; 6 | 7 | /** 8 | * @author lt_name 9 | */ 10 | public class MeleeWeapon extends BaseWeapon { 11 | 12 | protected final float knockBack; 13 | 14 | public MeleeWeapon(String name, Config config) { 15 | super(name, config); 16 | this.knockBack = Math.abs((float) config.getDouble("knockBack", 0.3D)); 17 | 18 | CompoundTag tag = this.getCompoundTag(); 19 | tag.putFloat("knockBack", this.knockBack); 20 | this.setCompoundTag(tag); 21 | } 22 | 23 | @Override 24 | public ItemManage.ItemType getItemType() { 25 | return ItemManage.ItemType.WEAPON_MELEE; 26 | } 27 | 28 | /** 29 | * @return 击退 30 | */ 31 | public float getKnockBack() { 32 | return this.knockBack; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/usersub/RecordCommand.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command.usersub; 2 | 3 | import cn.lanink.gunwar.command.base.BaseSubCommand; 4 | import cn.lanink.gunwar.gui.GuiCreate; 5 | import cn.nukkit.Player; 6 | import cn.nukkit.command.CommandSender; 7 | import cn.nukkit.command.data.CommandParameter; 8 | 9 | public class RecordCommand extends BaseSubCommand { 10 | 11 | public RecordCommand(String name) { 12 | super(name); 13 | } 14 | 15 | @Override 16 | public boolean canUser(CommandSender sender) { 17 | return sender.isPlayer(); 18 | } 19 | 20 | @Override 21 | public String[] getAliases() { 22 | return new String[0]; 23 | } 24 | 25 | @Override 26 | public boolean execute(CommandSender sender, String label, String[] args) { 27 | GuiCreate.sendGameRecord((Player) sender); 28 | return true; 29 | } 30 | 31 | @Override 32 | public CommandParameter[] getParameters() { 33 | return new CommandParameter[0]; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/adminsub/ReloadCommand.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command.adminsub; 2 | 3 | import cn.lanink.gunwar.command.base.BaseSubCommand; 4 | import cn.nukkit.command.CommandSender; 5 | import cn.nukkit.command.data.CommandParameter; 6 | 7 | public class ReloadCommand extends BaseSubCommand { 8 | 9 | public ReloadCommand(String name) { 10 | super(name); 11 | } 12 | 13 | @Override 14 | public boolean canUser(CommandSender sender) { 15 | return sender.isOp(); 16 | } 17 | 18 | @Override 19 | public String[] getAliases() { 20 | return new String[0]; 21 | } 22 | 23 | @Override 24 | public boolean execute(CommandSender sender, String label, String[] args) { 25 | this.gunWar.getGameRoomManager().reloadAllGameRoom(); 26 | sender.sendMessage(this.language.translateString("adminReload")); 27 | return true; 28 | } 29 | 30 | @Override 31 | public CommandParameter[] getParameters() { 32 | return new CommandParameter[0]; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/adminsub/UnloadCommand.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command.adminsub; 2 | 3 | import cn.lanink.gunwar.command.base.BaseSubCommand; 4 | import cn.nukkit.command.CommandSender; 5 | import cn.nukkit.command.data.CommandParameter; 6 | 7 | public class UnloadCommand extends BaseSubCommand { 8 | 9 | public UnloadCommand(String name) { 10 | super(name); 11 | } 12 | 13 | @Override 14 | public boolean canUser(CommandSender sender) { 15 | return sender.isOp(); 16 | } 17 | 18 | @Override 19 | public String[] getAliases() { 20 | return new String[0]; 21 | } 22 | 23 | @Override 24 | public boolean execute(CommandSender sender, String label, String[] args) { 25 | this.gunWar.getGameRoomManager().unloadAllGameRoom(); 26 | sender.sendMessage(this.language.translateString("adminUnload")); 27 | return true; 28 | } 29 | 30 | @Override 31 | public CommandParameter[] getParameters() { 32 | return new CommandParameter[0]; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/adminsub/AddWeapon.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command.adminsub; 2 | 3 | import cn.lanink.gunwar.command.base.BaseSubCommand; 4 | import cn.lanink.gunwar.gui.GuiCreate; 5 | import cn.nukkit.Player; 6 | import cn.nukkit.command.CommandSender; 7 | import cn.nukkit.command.data.CommandParameter; 8 | 9 | /** 10 | * @author lt_name 11 | */ 12 | public class AddWeapon extends BaseSubCommand { 13 | 14 | public AddWeapon(String name) { 15 | super(name); 16 | } 17 | 18 | @Override 19 | public boolean canUser(CommandSender sender) { 20 | return sender.isPlayer() && sender.isOp(); 21 | } 22 | 23 | @Override 24 | public String[] getAliases() { 25 | return new String[0]; 26 | } 27 | 28 | @Override 29 | public boolean execute(CommandSender sender, String label, String[] args) { 30 | GuiCreate.sendAdminItemAddWeaponMenu(((Player) sender)); 31 | return true; 32 | } 33 | 34 | @Override 35 | public CommandParameter[] getParameters() { 36 | return new CommandParameter[0]; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/event/GunWarPlayerDamageEvent.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.event; 2 | 3 | import cn.lanink.gunwar.room.base.BaseRoom; 4 | import cn.nukkit.Player; 5 | import cn.nukkit.event.Cancellable; 6 | import cn.nukkit.event.HandlerList; 7 | 8 | public class GunWarPlayerDamageEvent extends GunWarRoomPlayerEvent implements Cancellable { 9 | 10 | private static final HandlerList handlers = new HandlerList(); 11 | private Player damagePlayer; 12 | private float damage; 13 | 14 | public static HandlerList getHandlers() { 15 | return handlers; 16 | } 17 | 18 | public GunWarPlayerDamageEvent(BaseRoom room, Player player, Player damagePlayer, float damage) { 19 | this.room = room; 20 | this.player = player; 21 | this.damagePlayer = damagePlayer; 22 | this.damage = damage; 23 | } 24 | 25 | public Player getDamagePlayer() { 26 | return this.damagePlayer; 27 | } 28 | 29 | public void setDamage(float damage) { 30 | this.damage = damage; 31 | } 32 | 33 | public float getDamage() { 34 | return this.damage; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | # Supported languages: chs | kor | eng | rus | spa 2 | # 如果你想自定义语言文件请设置为xxx_customize, 例如chs_customize 并修改chs_customize.yml文件 3 | # If you want to customize the language file, please set it to xxx_customize, such as eng_customize and modify the eng_customize.yml file 4 | language: chs 5 | restoreWorld: true 6 | #在游戏内使用单独血量计算(Boss血条显示自身血量) 7 | #适合RPG或其他会修改玩家血量的服务器使用 8 | enableAloneHealth: true 9 | #允许非GunWar插件武器造成的伤害 10 | enableOtherWeaponDamage: false 11 | cmdUser: gunwar 12 | cmdAdmin: gunwaradmin 13 | #可以在游戏房间中使用的命令 14 | cmdWhitelist: 15 | - ban 16 | - kick 17 | - report 18 | 胜利执行命令: 19 | - me 我胜利了 20 | - tell "@p" 恭喜获得胜利!&con 21 | 失败执行命令: 22 | - me 我失败了 23 | - tell "@p" 很遗憾你失败了!&con 24 | 25 | QuitRoom: 26 | #退出房间执行命令 27 | cmd: [] 28 | 29 | #游戏内积分 (商店用) 30 | integral: 31 | #游戏开始时玩家基础积分 32 | Start_Base_Integral: 1000 33 | #击杀敌人获得积分 34 | Kill_Score: 10 35 | #击杀队友获得积分 36 | Kill_Team_Score: -10 37 | #安放炸弹获得积分 (仅爆破模式) 38 | Bomb_Score: 20 39 | #拆除炸弹获得积分 (仅爆破模式) 40 | Destroy_Score: 20 41 | #运回旗帜获得积分 (仅限夺旗模式) 42 | Flag_Get_Score: 20 43 | #回合胜利获得积分 44 | Round_Win_Score: 100 45 | #回合失败获得积分 46 | Round_Lose_Score: 50 -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/usersub/ListCommand.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command.usersub; 2 | 3 | import cn.lanink.gunwar.command.base.BaseSubCommand; 4 | import cn.nukkit.command.CommandSender; 5 | import cn.nukkit.command.data.CommandParameter; 6 | 7 | public class ListCommand extends BaseSubCommand { 8 | 9 | public ListCommand(String name) { 10 | super(name); 11 | } 12 | 13 | @Override 14 | public boolean canUser(CommandSender sender) { 15 | return true; 16 | } 17 | 18 | @Override 19 | public String[] getAliases() { 20 | return new String[] { "列表" }; 21 | } 22 | 23 | @Override 24 | public boolean execute(CommandSender sender, String label, String[] args) { 25 | StringBuilder list = new StringBuilder(); 26 | for (String string : this.gunWar.getGameRoomManager().getGameRoomMap().keySet()) { 27 | list.append(string).append(" "); 28 | } 29 | sender.sendMessage(this.language.translateString("listRoom", list)); 30 | return true; 31 | } 32 | 33 | @Override 34 | public CommandParameter[] getParameters() { 35 | return new CommandParameter[0]; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/adminsub/CreateRank.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command.adminsub; 2 | 3 | import cn.lanink.gunwar.command.base.BaseSubCommand; 4 | import cn.lanink.gunwar.gui.GuiCreate; 5 | import cn.nukkit.Player; 6 | import cn.nukkit.command.CommandSender; 7 | import cn.nukkit.command.data.CommandParamType; 8 | import cn.nukkit.command.data.CommandParameter; 9 | 10 | /** 11 | * @author LT_Name 12 | */ 13 | public class CreateRank extends BaseSubCommand { 14 | 15 | public CreateRank(String name) { 16 | super(name); 17 | } 18 | 19 | @Override 20 | public boolean canUser(CommandSender sender) { 21 | return sender.isPlayer() && sender.isOp(); 22 | } 23 | 24 | @Override 25 | public String[] getAliases() { 26 | return new String[0]; 27 | } 28 | 29 | @Override 30 | public boolean execute(CommandSender sender, String label, String[] args) { 31 | Player player = (Player) sender; 32 | GuiCreate.sendCreateRankMenu(player); 33 | return true; 34 | } 35 | 36 | @Override 37 | public CommandParameter[] getParameters() { 38 | return new CommandParameter[] { CommandParameter.newType("RankName", CommandParamType.TEXT) }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/entity/flag/EntityFlag.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.entity.flag; 2 | 3 | import cn.nukkit.entity.EntityHuman; 4 | import cn.nukkit.level.format.FullChunk; 5 | import cn.nukkit.nbt.tag.CompoundTag; 6 | 7 | public class EntityFlag extends EntityHuman { 8 | 9 | private int flag = 0; 10 | 11 | public EntityFlag(FullChunk chunk, CompoundTag nbt) { 12 | super(chunk, nbt); 13 | this.setNameTagVisible(false); 14 | this.setNameTagAlwaysVisible(false); 15 | } 16 | 17 | @Override 18 | public boolean onUpdate(int currentTick) { 19 | if(currentTick%2 == 0) { 20 | if (flag < 20) { 21 | this.yaw++; 22 | }else { 23 | this.yaw--; 24 | } 25 | this.flag++; 26 | if (this.flag >= 40) { 27 | this.flag = 0; 28 | } 29 | } 30 | return super.onUpdate(currentTick); 31 | } 32 | 33 | @Override 34 | public float getHeight() { 35 | return 1.6F; 36 | } 37 | 38 | @Override 39 | public float getLength() { 40 | return 0.3F; 41 | } 42 | 43 | @Override 44 | public float getWidth() { 45 | return 0.3F; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/entity/tower/EntityCrossbowTower.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.entity.tower; 2 | 3 | import cn.lanink.gamecore.GameCore; 4 | import cn.lanink.gunwar.room.base.BaseRoom; 5 | import cn.lanink.gunwar.room.base.Team; 6 | import cn.nukkit.level.format.FullChunk; 7 | import cn.nukkit.nbt.tag.CompoundTag; 8 | 9 | /** 10 | * @author LT_Name 11 | */ 12 | public class EntityCrossbowTower extends EntityBaseTower { 13 | 14 | private static final TowerDefinition CROSSBOW_TOWER_DEFINITION; 15 | 16 | static { 17 | CROSSBOW_TOWER_DEFINITION = new TowerDefinition(); 18 | CROSSBOW_TOWER_DEFINITION.setName("CrossbowTower"); 19 | CROSSBOW_TOWER_DEFINITION.setMaxHealth(100); 20 | CROSSBOW_TOWER_DEFINITION.setAttackDamage(4); 21 | CROSSBOW_TOWER_DEFINITION.setAttackSpeed(30); 22 | CROSSBOW_TOWER_DEFINITION.setAttackMinRange(3); 23 | CROSSBOW_TOWER_DEFINITION.setAttackMaxRange(15); 24 | } 25 | 26 | public EntityCrossbowTower(BaseRoom room, Team team, FullChunk chunk, CompoundTag nbt) { 27 | super(room, team, chunk, nbt); 28 | this.setTowerDefinition(CROSSBOW_TOWER_DEFINITION); 29 | this.setSkin(GameCore.MODEL.getModel("GunWar:CrossbowTower")); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/UserCommand.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command; 2 | 3 | import cn.lanink.gunwar.command.base.BaseCommand; 4 | import cn.lanink.gunwar.command.usersub.JoinCommand; 5 | import cn.lanink.gunwar.command.usersub.ListCommand; 6 | import cn.lanink.gunwar.command.usersub.QuitCommand; 7 | import cn.lanink.gunwar.command.usersub.RecordCommand; 8 | import cn.lanink.gunwar.gui.GuiCreate; 9 | import cn.nukkit.Player; 10 | import cn.nukkit.command.CommandSender; 11 | 12 | public class UserCommand extends BaseCommand { 13 | 14 | public UserCommand(String name) { 15 | super(name, "GunWar 命令"); 16 | this.setPermission("GunWar.command.user"); 17 | this.addSubCommand(new JoinCommand("join")); 18 | this.addSubCommand(new QuitCommand("quit")); 19 | this.addSubCommand(new ListCommand("list")); 20 | this.addSubCommand(new RecordCommand("record")); 21 | this.loadCommandBase(); 22 | } 23 | 24 | @Override 25 | public void sendHelp(CommandSender sender) { 26 | sender.sendMessage(this.language.translateString("userHelp", this.getName())); 27 | } 28 | 29 | @Override 30 | public void sendUI(CommandSender sender) { 31 | GuiCreate.sendUserMenu((Player) sender); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/room/classic/ClassicModeRoom.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.room.classic; 2 | 3 | import cn.lanink.gamecore.utils.exception.RoomLoadException; 4 | import cn.lanink.gunwar.room.base.BaseRoundModeRoom; 5 | import cn.lanink.gunwar.room.base.PlayerGameData; 6 | import cn.lanink.gunwar.room.base.Team; 7 | import cn.nukkit.level.Level; 8 | import cn.nukkit.utils.Config; 9 | 10 | /** 11 | * 房间 12 | */ 13 | public class ClassicModeRoom extends BaseRoundModeRoom { 14 | 15 | public ClassicModeRoom(Level level, Config config) throws RoomLoadException { 16 | super(level, config); 17 | } 18 | 19 | @Override 20 | protected void checkTeamPlayerCount() { 21 | int red = 0; 22 | int blue = 0; 23 | for (PlayerGameData gameData : this.getPlayerDataMap().values()) { 24 | if (gameData.getTeam() == Team.RED) { 25 | red++; 26 | } else if (gameData.getTeam() == Team.BLUE) { 27 | blue++; 28 | } 29 | } 30 | if (red == 0) { 31 | this.roundEnd(Team.BLUE); 32 | this.gameTime = this.getSetGameTime(); 33 | } else if (blue == 0) { 34 | this.roundEnd(Team.RED); 35 | this.gameTime = this.getSetGameTime(); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/AdminCommand.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command; 2 | 3 | import cn.lanink.gunwar.command.adminsub.*; 4 | import cn.lanink.gunwar.command.base.BaseCommand; 5 | import cn.lanink.gunwar.gui.GuiCreate; 6 | import cn.nukkit.Player; 7 | import cn.nukkit.command.CommandSender; 8 | 9 | public class AdminCommand extends BaseCommand { 10 | 11 | public AdminCommand(String name) { 12 | super(name, "GunWar 管理命令"); 13 | this.setPermission("GunWar.command.admin"); 14 | //游戏内使用命令不区分大小写! 15 | this.addSubCommand(new CreateRoom("CreateRoom")); 16 | this.addSubCommand(new SetRoom("SetRoom")); 17 | this.addSubCommand(new StartRoom("StartRoom")); 18 | this.addSubCommand(new StopRoom("StopRoom")); 19 | this.addSubCommand(new ReloadCommand("ReloadRoom")); 20 | this.addSubCommand(new UnloadCommand("UnloadRoom")); 21 | this.addSubCommand(new AddWeapon("AddWeapon")); 22 | this.addSubCommand(new CreateRank("CreateRank")); 23 | this.loadCommandBase(); 24 | } 25 | 26 | @Override 27 | public void sendHelp(CommandSender sender) { 28 | sender.sendMessage(this.language.translateString("adminHelp", this.getName())); 29 | } 30 | 31 | @Override 32 | public void sendUI(CommandSender sender) { 33 | GuiCreate.sendAdminMenu((Player) sender); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/supplier/pages/LinkItem.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.supplier.pages; 2 | 3 | import cn.lanink.gamecore.api.Info; 4 | import cn.nukkit.item.Item; 5 | import lombok.Getter; 6 | import lombok.ToString; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | @ToString 11 | public class LinkItem { 12 | 13 | private final int slotPos; 14 | private final Item item; 15 | 16 | @Info("从 SupplyConfig 中的 pageConfigMap 获取 page数据") 17 | @Getter 18 | private final String pageFileName; 19 | private final Item afterClick; 20 | 21 | public int getSlotPos() { 22 | return this.slotPos; 23 | } 24 | 25 | public LinkItem(@NotNull Item item, int slotPos, @NotNull String pageFileName) { 26 | this(item, slotPos, pageFileName, null); 27 | } 28 | 29 | public LinkItem(@NotNull Item item, int slotPos, @NotNull String pageFileName, @Nullable Item afterClick) { 30 | this.item = item; 31 | this.slotPos = slotPos; 32 | this.pageFileName = pageFileName; 33 | this.afterClick = afterClick; 34 | } 35 | 36 | public Item getItem() { 37 | return this.item.clone(); 38 | } 39 | 40 | public Item getAfterClick() { 41 | if (this.afterClick != null) { 42 | return this.afterClick.clone(); 43 | } 44 | return null; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /README(zh-CN).md: -------------------------------------------------------------------------------- 1 | # Gunwar 2 | 3 | [![License](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](LICENSE) 4 | ![Java CI](https://github.com/MemoriesOfTime/GunWar/workflows/Java%20CI/badge.svg) 5 | [![bilibili](https://img.shields.io/badge/Link-bilibili-ff69b4)](https://www.bilibili.com/video/BV12A411t7Gr/) 6 | 7 | ## 切换语言 8 | 9 | ![Github](https://img.shields.io/badge/简体中文[已选择]-100%25-brightgreen) 10 | [![Github](https://img.shields.io/badge/English-100%25-brightgreen)](https://github.com/MemoriesOfTime/GunWar/blob/master/README.md) 11 | 12 | ## 介绍 13 | 14 | 枪械战争是一款普通的团队竞技游戏,拥有高达4种不同的模式供你选择。你需要去运用你手中的武器装备去打败对面以赢取胜利。本款插件操作简单、富有乐趣,同时这也是一款快节奏型的小游戏,你能成为最终的胜利者么? 15 | 16 | ## 特色 17 | 18 | **四种不同的模式!** 包括歼灭战、团队战、爆破战和夺旗战 19 | 20 | **排行榜系统!** 让你的每一次胜利充满成就感。你能成为排行榜中的领头者么? 21 | 22 | **高度自定义配置!** 除了基础配置以外,你还可以设置玩家的初始物品,可设置原生物品,也可设置自定义的物品类型来辅助原生物品(如:近战武器,投掷武器,枪械);同时也可以设置旗子的皮肤等等 23 | 24 | **局内商店系统!** 可设置商店可购买物品及其所需的积分! 25 | 26 | **计分板支持!** 计分板会实时展示得分、剩余时间等信息! 27 | 28 | **虚拟血量支持!** 玩家受到伤害会通过虚拟血量计算,并显示在头顶的boss血量条上! 29 | 30 | **简易GUI操作!** 你可以轻松地设置或编辑每一个房间。大部分配置项都可轻松更改。 31 | 32 | **局后执行指定指令!** 你可以奖赏或惩罚胜利或失败的玩家。 33 | 34 | **多语言支持!** 你可以选择你想使用的语言,也可以创建属于自己的语言文件! 35 | 36 | ## 游戏内截图 37 | 38 | ![](pic/zh-CN/screenshot_01.png) 39 | 40 | ![](pic/zh-CN/screenshot_02.png) 41 | 42 | ![](pic/zh-CN/screenshot_03.png) 43 | 44 | ## Bug及意见反馈 45 | 46 | 如果您遇到问题,可以在原贴(mcbbs/minebbs)下面向我们反馈。同时,前往 [Discord](https://discord.gg/pJjQDQC)或者在此处发Issue也是个不错之选!. 47 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/adminsub/StopRoom.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command.adminsub; 2 | 3 | import cn.lanink.gunwar.command.base.BaseSubCommand; 4 | import cn.lanink.gunwar.room.base.BaseRoom; 5 | import cn.nukkit.Player; 6 | import cn.nukkit.command.CommandSender; 7 | import cn.nukkit.command.data.CommandParameter; 8 | 9 | /** 10 | * @author lt_name 11 | */ 12 | public class StopRoom extends BaseSubCommand { 13 | 14 | public StopRoom(String name) { 15 | super(name); 16 | } 17 | 18 | @Override 19 | public boolean canUser(CommandSender sender) { 20 | return sender.isPlayer() && sender.isOp(); 21 | } 22 | 23 | @Override 24 | public String[] getAliases() { 25 | return new String[0]; 26 | } 27 | 28 | @Override 29 | public boolean execute(CommandSender sender, String label, String[] args) { 30 | Player player = (Player) sender; 31 | BaseRoom room = this.gunWar.getGameRoomManager().getGameRoom(player.getLevel().getFolderName()); 32 | if (room != null) { 33 | room.endGame(); 34 | sender.sendMessage(this.language.translateString("adminStopRoom")); 35 | }else { 36 | sender.sendMessage(this.language.translateString("adminLevelNoRoom")); 37 | } 38 | return true; 39 | } 40 | 41 | @Override 42 | public CommandParameter[] getParameters() { 43 | return new CommandParameter[0]; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/room/base/PlayerGameData.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.room.base; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.nukkit.Player; 5 | import lombok.Data; 6 | 7 | import java.util.HashMap; 8 | 9 | /** 10 | * @author LT_Name 11 | */ 12 | @Data 13 | public class PlayerGameData { 14 | 15 | private final Player player; 16 | private Team team; 17 | private float health; 18 | private int invincibleTime; 19 | private int integral; 20 | private int killCount; 21 | private int assistsKillCount; 22 | 23 | private Player lastDamagePlayer; 24 | private final HashMap damager = new HashMap<>(); 25 | 26 | public PlayerGameData(Player player) { 27 | this.player = player; 28 | this.team = Team.NULL; 29 | if (GunWar.getInstance().isEnableAloneHealth()) { 30 | this.health = 20F; 31 | } else { 32 | this.health = player.getMaxHealth(); 33 | } 34 | this.integral = Integer.MAX_VALUE; 35 | this.killCount = 0; 36 | this.assistsKillCount = 0; 37 | } 38 | 39 | public void setHealth(float health) { 40 | this.health = health; 41 | if (!GunWar.getInstance().isEnableAloneHealth()) { 42 | this.player.setHealth(health); 43 | } 44 | } 45 | 46 | public void addKillCount() { 47 | this.killCount++; 48 | } 49 | 50 | public void addAssistsKillCount() { 51 | this.assistsKillCount++; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/entity/EntityGunWarBombBlock.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.entity; 2 | 3 | import cn.lanink.gamecore.utils.EntityUtils; 4 | import cn.nukkit.entity.EntityHuman; 5 | import cn.nukkit.level.format.FullChunk; 6 | import cn.nukkit.nbt.tag.CompoundTag; 7 | 8 | /** 9 | * 拆弹点击判断用 炸弹实体 10 | * 11 | * @author lt_name 12 | */ 13 | public class EntityGunWarBombBlock extends EntityHuman { 14 | 15 | public EntityGunWarBombBlock(FullChunk chunk, CompoundTag nbt) { 16 | super(chunk, nbt.putCompound("Skin", new CompoundTag())); 17 | this.setNameTag(""); 18 | this.setNameTagVisible(false); 19 | this.setNameTagAlwaysVisible(false); 20 | this.setDataFlag( 21 | EntityUtils.getEntityField("DATA_FLAGS", DATA_FLAGS), 22 | EntityUtils.getEntityField("DATA_FLAG_INVISIBLE", DATA_FLAG_INVISIBLE), 23 | true 24 | ); 25 | } 26 | 27 | @Override 28 | protected void initEntity() { 29 | super.initEntity(); 30 | this.setMaxHealth(20); 31 | } 32 | 33 | @Override 34 | public boolean onUpdate(int currentTick) { 35 | this.deadTicks = 0; 36 | return super.onUpdate(currentTick); 37 | } 38 | 39 | @Override 40 | public float getLength() { 41 | return 1.1F; 42 | } 43 | 44 | @Override 45 | public float getWidth() { 46 | return 1.1F; 47 | } 48 | 49 | @Override 50 | public float getHeight() { 51 | return 1.1F; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/base/BaseSubCommand.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command.base; 2 | 3 | import cn.lanink.gamecore.utils.Language; 4 | import cn.lanink.gunwar.GunWar; 5 | import cn.nukkit.command.CommandSender; 6 | import cn.nukkit.command.data.CommandParameter; 7 | 8 | 9 | /** 10 | * @author SmallasWater 11 | */ 12 | public abstract class BaseSubCommand { 13 | 14 | protected GunWar gunWar = GunWar.getInstance(); 15 | 16 | protected Language language = gunWar.getLanguage(); 17 | 18 | private final String name; 19 | 20 | protected BaseSubCommand(String name) { 21 | this.name = name.toLowerCase(); 22 | } 23 | 24 | /** 25 | * @param sender CommandSender 26 | * @return boolean 27 | */ 28 | public abstract boolean canUser(CommandSender sender); 29 | 30 | /** 31 | * 获取名称 32 | * @return string 33 | */ 34 | public String getName(){ 35 | return name; 36 | } 37 | 38 | /** 39 | * 获取别名 40 | * @return string[] 41 | */ 42 | public abstract String[] getAliases(); 43 | 44 | /** 45 | * 命令响应 46 | * @param sender the sender - CommandSender 47 | * @param args The arrugements - String[] 48 | * @param label label.. 49 | * @return true if true 50 | */ 51 | public abstract boolean execute(CommandSender sender, String label, String[] args); 52 | 53 | /** 54 | * 指令参数. 55 | * @return 提示参数 56 | * */ 57 | abstract public CommandParameter[] getParameters(); 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/ui/advanced/AdvancedPageLinkItem.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils.ui.advanced; 2 | 3 | import cn.lanink.gamecore.form.inventory.advanced.AdvancedFakeChestInventory; 4 | import cn.lanink.gamecore.form.inventory.responsible.ResponseItem; 5 | import cn.lanink.gunwar.supplier.pages.SupplyPageConfig; 6 | import cn.nukkit.Player; 7 | import cn.nukkit.event.inventory.InventoryClickEvent; 8 | import cn.nukkit.item.Item; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class AdvancedPageLinkItem extends ResponseItem { 12 | 13 | private final SupplyPageConfig pageConfig; 14 | 15 | public AdvancedPageLinkItem(@NotNull Item item, @NotNull SupplyPageConfig nextPageConfig) { 16 | super(item); 17 | this.pageConfig = nextPageConfig; 18 | } 19 | 20 | @Override 21 | public void callClick(@NotNull InventoryClickEvent clickEvent, @NotNull Player player) { 22 | if (!(clickEvent.getInventory() instanceof AdvancedFakeChestInventory)) { 23 | return; 24 | } 25 | AdvancedFakeChestInventory newWindow = this.pageConfig.generateWindow((AdvancedFakeChestInventory) clickEvent.getInventory()); 26 | if (this.pageConfig.getLinkItems() != null && this.pageConfig.getLinkItems().get(clickEvent.getSlot()).getAfterClick() != null) { 27 | Item afterClick = this.pageConfig.getLinkItems().get(clickEvent.getSlot()).getAfterClick().setCustomName(getItem().getCustomName()); 28 | newWindow.setItem(clickEvent.getSlot(), afterClick); 29 | } 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/ui/advanced/AdvancedBuyItem.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils.ui.advanced; 2 | 3 | import cn.lanink.gamecore.form.inventory.responsible.ResponseItem; 4 | import cn.lanink.gunwar.GunWar; 5 | import cn.lanink.gunwar.room.base.BaseRoom; 6 | import cn.lanink.gunwar.supplier.items.SupplyItemConfig; 7 | import cn.nukkit.Player; 8 | import cn.nukkit.event.inventory.InventoryClickEvent; 9 | import cn.nukkit.item.Item; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | public class AdvancedBuyItem extends ResponseItem { 13 | 14 | private final SupplyItemConfig itemConfig; 15 | 16 | public AdvancedBuyItem(@NotNull Item item, @NotNull SupplyItemConfig itemConfig) { 17 | super(item); 18 | this.itemConfig = itemConfig; 19 | } 20 | 21 | @Override 22 | public void callClick(@NotNull InventoryClickEvent clickEvent, @NotNull Player player) { 23 | for (BaseRoom room : GunWar.getInstance().getGameRoomManager().getGameRoomMap().values()) { 24 | if (room.isPlaying(player)) { 25 | int nowIntegral = room.getPlayerIntegral(player); 26 | if (nowIntegral < this.itemConfig.getNeedIntegral()) { 27 | player.sendTip("您没有足够的积分来购买!"); 28 | return; 29 | } 30 | room.setPlayerIntegral(player, nowIntegral - this.itemConfig.getNeedIntegral()); 31 | player.getInventory().addItem(this.itemConfig.getItems()); 32 | player.sendTip("购买成功!"); 33 | } 34 | } 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/room/team/TeamModeRoom.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.room.team; 2 | 3 | import cn.lanink.gamecore.utils.exception.RoomLoadException; 4 | import cn.lanink.gunwar.room.base.BaseRespawnModeRoom; 5 | import cn.lanink.gunwar.room.base.Team; 6 | import cn.nukkit.Player; 7 | import cn.nukkit.entity.Entity; 8 | import cn.nukkit.level.Level; 9 | import cn.nukkit.utils.Config; 10 | 11 | /** 12 | * @author LT_Name 13 | */ 14 | public class TeamModeRoom extends BaseRespawnModeRoom { 15 | 16 | /** 17 | * 初始化 18 | * 19 | * @param level 游戏世界 20 | * @param config 配置文件 21 | */ 22 | public TeamModeRoom(Level level, Config config) throws RoomLoadException { 23 | super(level, config); 24 | 25 | //针对未配置的情况,团队模式需要缩短默认的时间 26 | this.respawnNeedTime = config.getInt("respawn-need-time", 3); 27 | } 28 | 29 | @Override 30 | public void timeTask() { 31 | super.timeTask(); 32 | if (!this.isRoundEnd()) { 33 | if (this.blueScore >= this.victoryScore) { 34 | this.roundEnd(Team.BLUE); 35 | } else if (this.redScore >= this.victoryScore) { 36 | this.roundEnd(Team.RED); 37 | } 38 | } 39 | } 40 | 41 | @Override 42 | public void playerDeath(Player player, Entity damager, String killMessage) { 43 | if (damager instanceof Player) { 44 | if (this.getPlayerTeamAccurate(player) == Team.RED) { 45 | this.blueScore++; 46 | }else { 47 | this.redScore++; 48 | } 49 | } 50 | super.playerDeath(player, damager, killMessage); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/rsnpc/RsNpcVariableV2.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils.rsnpc; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.lanink.gunwar.room.base.BaseRoom; 5 | import cn.nukkit.Player; 6 | import com.smallaswater.npc.data.RsNpcConfig; 7 | import com.smallaswater.npc.variable.BaseVariableV2; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | /** 13 | * @author LT_Name 14 | */ 15 | public class RsNpcVariableV2 extends BaseVariableV2 { 16 | 17 | @Override 18 | public void onUpdate(Player player, RsNpcConfig rsNpcConfig) { 19 | HashMap map = new HashMap<>(); 20 | int all = 0; 21 | for (BaseRoom room : GunWar.getInstance().getGameRoomManager().getGameRoomMap().values()) { 22 | map.put(room.getGameMode(), 23 | map.getOrDefault(room.getGameMode(), 0) + room.getPlayerDataMap().size()); 24 | all += room.getPlayerDataMap().size(); 25 | } 26 | for (Map.Entry entry : map.entrySet()) { 27 | this.addVariable("{GunWarRoomPlayerNumber" + entry.getKey() + "}", entry.getValue().toString()); 28 | } 29 | 30 | HashMap map1 = new HashMap<>(); 31 | for (BaseRoom room : GunWar.getInstance().getGameRoomManager().getGameRoomMap().values()) { 32 | map1.put(room.getLevelName(), map1.getOrDefault(room.getLevelName(), 0) + room.getPlayerDataMap().size()); 33 | } 34 | for (Map.Entry entry : map1.entrySet()) { 35 | this.addVariable("{GunWarLevelPlayerNumber" + entry.getKey() + "}", entry.getValue().toString()); 36 | } 37 | 38 | this.addVariable("{GunWarRoomPlayerNumberAll}", String.valueOf(all)); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/adminsub/StartRoom.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command.adminsub; 2 | 3 | import cn.lanink.gunwar.command.base.BaseSubCommand; 4 | import cn.lanink.gunwar.room.base.BaseRoom; 5 | import cn.nukkit.Player; 6 | import cn.nukkit.command.CommandSender; 7 | import cn.nukkit.command.data.CommandParameter; 8 | 9 | /** 10 | * @author lt_name 11 | */ 12 | public class StartRoom extends BaseSubCommand { 13 | 14 | public StartRoom(String name) { 15 | super(name); 16 | } 17 | 18 | @Override 19 | public boolean canUser(CommandSender sender) { 20 | return sender.isPlayer() && sender.isOp(); 21 | } 22 | 23 | @Override 24 | public String[] getAliases() { 25 | return new String[0]; 26 | } 27 | 28 | @Override 29 | public boolean execute(CommandSender sender, String label, String[] args) { 30 | Player player = (Player) sender; 31 | BaseRoom room = this.gunWar.getGameRoomManager().getGameRoom(player.getLevel().getFolderName()); 32 | if (room != null) { 33 | if (room.getPlayerDataMap().size() >= 2) { 34 | if (room.getStatus() == 1) { 35 | room.startGame(); 36 | sender.sendMessage(this.language.translateString("adminStartRoom")); 37 | }else { 38 | sender.sendMessage(this.language.translateString("adminStartRoomIsPlaying")); 39 | } 40 | }else { 41 | sender.sendMessage(this.language.translateString("adminStartRoomNoPlayer")); 42 | } 43 | }else { 44 | sender.sendMessage(this.language.translateString("adminLevelNoRoom")); 45 | } 46 | return true; 47 | } 48 | 49 | @Override 50 | public CommandParameter[] getParameters() { 51 | return new CommandParameter[0]; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/nsgb/GunWarDataGamePlayerPojoUtils.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils.nsgb; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.lanink.gunwar.room.base.PlayerGameData; 5 | import cn.nsgamebase.api.GbGameApi; 6 | import cn.nukkit.utils.Config; 7 | 8 | /** 9 | * @author LT_Name 10 | */ 11 | public class GunWarDataGamePlayerPojoUtils { 12 | 13 | public static GunWarDataGamePlayerPojo getGamePlayerPojo() { 14 | GunWarDataGamePlayerPojo pojo = new GunWarDataGamePlayerPojo(); 15 | 16 | pojo.registerKey("killCount", "击杀数"); 17 | 18 | return pojo; 19 | } 20 | 21 | public static void onWin(PlayerGameData playerData) { 22 | GunWarDataGamePlayerPojo pojo = getGamePlayerPojo(); 23 | pojo.add("played"); 24 | pojo.add("win"); 25 | pojo.add("killCount", playerData.getKillCount()); 26 | Config gunWarConfig = GunWar.getInstance().getConfig(); 27 | int money = gunWarConfig.getInt("fapWinIntegral.money"); 28 | int exp = gunWarConfig.getInt("fapWinIntegral.exp"); 29 | int maxMultiplier = gunWarConfig.getInt("fapWinIntegral.maxMultiplier"); 30 | GbGameApi.saveAndReward(playerData.getPlayer().getName(), "GunWar", pojo, money, exp, maxMultiplier); 31 | } 32 | 33 | public static void onLose(PlayerGameData playerData) { 34 | GunWarDataGamePlayerPojo pojo = getGamePlayerPojo(); 35 | 36 | pojo.add("played"); 37 | pojo.add("killCount", playerData.getKillCount()); 38 | Config gunWarConfig = GunWar.getInstance().getConfig(); 39 | int money = gunWarConfig.getInt("fapLoseIntegral.money"); 40 | int exp = gunWarConfig.getInt("fapLoseIntegral.exp"); 41 | int maxMultiplier = gunWarConfig.getInt("fapLoseIntegral.maxMultiplier"); 42 | GbGameApi.saveAndReward(playerData.getPlayer().getName(), "GunWar", pojo, money, exp, maxMultiplier); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/usersub/QuitCommand.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command.usersub; 2 | 3 | import cn.lanink.gunwar.command.base.BaseSubCommand; 4 | import cn.lanink.gunwar.room.base.BaseRoom; 5 | import cn.lanink.teamsystem.TeamSystem; 6 | import cn.lanink.teamsystem.team.Team; 7 | import cn.nukkit.Player; 8 | import cn.nukkit.command.CommandSender; 9 | import cn.nukkit.command.data.CommandParameter; 10 | 11 | public class QuitCommand extends BaseSubCommand { 12 | 13 | public QuitCommand(String name) { 14 | super(name); 15 | } 16 | 17 | @Override 18 | public boolean canUser(CommandSender sender) { 19 | return sender.isPlayer(); 20 | } 21 | 22 | @Override 23 | public String[] getAliases() { 24 | return new String[] { "退出" }; 25 | } 26 | 27 | @Override 28 | public boolean execute(CommandSender sender, String label, String[] args) { 29 | Player player = (Player) sender; 30 | 31 | if (this.gunWar.isHasTeamSystem()) { 32 | Team team = TeamSystem.Companion.getTeamByPlayer(player); 33 | if (team != null) { 34 | if (!team.isTeamLeader(player)) { 35 | sender.sendMessage("[GunWar-TeamSystem] 你不是队长,无法主动退出游戏!"); 36 | sender.sendMessage("[GunWar-TeamSystem] 请让队长退出游戏或先退出队伍!!"); 37 | return true; 38 | } 39 | } 40 | } 41 | 42 | for (BaseRoom room : this.gunWar.getGameRoomManager().getGameRoomMap().values()) { 43 | if (room.isPlaying(player)) { 44 | room.quitRoom(player); 45 | return true; 46 | } 47 | } 48 | sender.sendMessage(this.language.translateString("quitRoomNotInRoom")); 49 | return true; 50 | } 51 | 52 | @Override 53 | public CommandParameter[] getParameters() { 54 | return new CommandParameter[0]; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/event/GunWarSwapTeamEvent.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.event; 2 | 3 | import cn.lanink.gunwar.room.blasting.BlastingModeRoom; 4 | import cn.nukkit.Player; 5 | import cn.nukkit.event.Cancellable; 6 | import cn.nukkit.event.HandlerList; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | 10 | import java.util.LinkedList; 11 | 12 | /** 13 | * 爆破模式队伍交换事件 14 | * 15 | * @author LT_Name 16 | */ 17 | public class GunWarSwapTeamEvent extends GunWarRoomEvent implements Cancellable { 18 | 19 | private static final HandlerList handlers = new HandlerList(); 20 | 21 | public static HandlerList getHandlers() { 22 | return handlers; 23 | } 24 | 25 | @Getter 26 | protected final LinkedList oldRedTeam; 27 | @Getter 28 | protected final LinkedList oldBlueTeam; 29 | @Getter 30 | protected final int oldRedScore; 31 | @Getter 32 | protected final int oldBlueScore; 33 | 34 | @Getter 35 | @Setter 36 | protected LinkedList newRedTeam; 37 | @Getter 38 | @Setter 39 | protected LinkedList newBlueTeam; 40 | @Getter 41 | @Setter 42 | protected int newRedScore; 43 | @Getter 44 | @Setter 45 | protected int newBlueScore; 46 | 47 | public GunWarSwapTeamEvent(BlastingModeRoom room, LinkedList oldRedTeam, LinkedList oldBlueTeam, int oldRedScore, int oldBlueScore) { 48 | this.room = room; 49 | this.oldRedTeam = oldRedTeam; 50 | this.oldBlueTeam = oldBlueTeam; 51 | this.oldRedScore = oldRedScore; 52 | this.oldBlueScore = oldBlueScore; 53 | 54 | this.newRedTeam = new LinkedList<>(this.oldBlueTeam); 55 | this.newBlueTeam = new LinkedList<>(this.oldRedTeam); 56 | this.newRedScore = this.oldBlueScore; 57 | this.newBlueScore = this.oldRedScore; 58 | } 59 | 60 | @Override 61 | public BlastingModeRoom getRoom() { 62 | return (BlastingModeRoom) this.room; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GunWar 2 | 3 | [![License](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](LICENSE) 4 | ![Java CI](https://github.com/MemoriesOfTime/GunWar/workflows/Java%20CI/badge.svg) 5 | [![bilibili](https://img.shields.io/badge/Link-bilibili-ff69b4)](https://www.bilibili.com/video/BV12A411t7Gr/) 6 | 7 | ## Switch between Languages? 8 | 9 | [![Github](https://img.shields.io/badge/简体中文-100%25-brightgreen)](https://github.com/MemoriesOfTime/GunWar/blob/master/README(zh-CN).md) 10 | ![Github](https://img.shields.io/badge/English[Selected]-100%25-brightgreen) 11 | 12 | ## Intro 13 | 14 | Gunwar is a simple team war with four different modes. You need to battle enemy team with different equipments and the ultimate target is to win the game. It is easy to manage, fun to play and extremely fast-paced and exciting game that you and your players will enjoy a lot! 15 | 16 | ## Features 17 | 18 | **Four different modes!** Including Elimination Match, Team Death Match, Team Match, Take The Flag Match. 19 | 20 | **Rankinglist System!** All players included. Can you be the best player of all? 21 | 22 | **Customizable configurations!** You can set players' initial items, including vanilla items and customized items(Melee, Projectile, Weapon_gun) 23 | 24 | **ScoreBoard & Dummy HealthBar Support!** Scoreboard will display all useful information for you while Dummy Bossbar will display your health status. 25 | 26 | **Simple GUI management!** You can easily set or modify every room. All simplified for easy configuration! 27 | 28 | **Run given commands!** You can reward or punish your players, based on who wins and loses! 29 | 30 | **Multi-languages support!** You can choose a existed language you like. And you can make your own language file. 31 | 32 | ## In-game Screenshots 33 | 34 | ![](pic/en-US/screenshot_01.jpg) 35 | 36 | ![](pic/en-US/screenshot_02.jpg) 37 | 38 | ![](pic/en-US/screenshot_03.jpg) 39 | 40 | ## Bugs & Reports 41 | 42 | If you come across any bug or problem while using it, you can report it on [Discord](https://discord.gg/pJjQDQC), or send a issue here to us. 43 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/supplier/items/SupplyItemConfig.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.supplier.items; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.lanink.gunwar.item.ItemManage; 5 | import cn.lanink.gunwar.utils.exception.supply.SupplyConfigLoadException; 6 | import cn.nukkit.item.Item; 7 | import cn.nukkit.utils.Config; 8 | import lombok.Getter; 9 | import lombok.ToString; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.io.File; 13 | import java.util.List; 14 | 15 | @ToString 16 | public class SupplyItemConfig { 17 | 18 | @Getter 19 | private final String fileName; 20 | @Getter 21 | private final Config config; 22 | 23 | @Getter 24 | private final String title; 25 | @Getter 26 | private final String subTitle; 27 | private final List items; 28 | @Getter 29 | private final int slotPos; 30 | @Getter 31 | private final int needIntegral; 32 | 33 | public SupplyItemConfig(@NotNull String fileName, @NotNull File fileConfig) throws SupplyConfigLoadException { 34 | this.fileName = fileName; 35 | this.config = new Config(fileConfig, Config.YAML); 36 | 37 | this.title = this.config.getString("title"); 38 | this.subTitle = this.config.getString("subTitle"); 39 | 40 | this.slotPos = this.config.getInt("pos"); 41 | 42 | this.needIntegral = this.config.getInt("needIntegral", 500); 43 | if (this.needIntegral <= 0) { 44 | GunWar.getInstance().getLogger().warning("商店物品:" + this.fileName + " 需要积分为0!玩家可无限购买!"); 45 | } 46 | 47 | this.items = this.config.getStringList("items"); 48 | Item[] itemArray = this.items.stream().map(ItemManage::of).toArray(Item[]::new); //全部读取一次,检查格式是否正确 49 | if (itemArray.length == 0) { 50 | throw new SupplyConfigLoadException("商店物品:" + this.fileName + " 无法正确加载物品!请检查配置!"); 51 | } 52 | } 53 | 54 | public Item getItem() { 55 | return ItemManage.of(this.items.get(0)); 56 | } 57 | 58 | public Item[] getItems() { 59 | return this.items.stream().map(ItemManage::of).toArray(Item[]::new); 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/supplier/SupplyConfigManager.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.supplier; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.lanink.gunwar.utils.exception.supply.SupplyConfigLoadException; 5 | import lombok.Getter; 6 | 7 | import java.io.File; 8 | import java.util.Arrays; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.Objects; 12 | import java.util.concurrent.atomic.AtomicInteger; 13 | 14 | public class SupplyConfigManager { 15 | 16 | private static final GunWar GUN_WAR = GunWar.getInstance(); 17 | 18 | @Getter 19 | private static final Map SUPPLY_CONFIG_MAP = new HashMap<>(); 20 | 21 | private SupplyConfigManager() throws IllegalArgumentException { 22 | throw new IllegalArgumentException("哎呀!你不能实例化这个类!"); 23 | } 24 | 25 | public static void loadAllSupplyConfig() { 26 | File dir = new File(GUN_WAR.getDataFolder(), "/Supply/"); 27 | if (!dir.exists()) { 28 | dir.mkdirs(); 29 | } 30 | GUN_WAR.saveResource("Supply/DefaultSupply/items/DemoGun.yml", GunWar.debug); 31 | GUN_WAR.saveResource("Supply/DefaultSupply/pages/Main.yml", GunWar.debug); 32 | File[] files = dir.listFiles(); 33 | if (files == null) { 34 | return; 35 | } 36 | AtomicInteger count = new AtomicInteger(); 37 | Arrays.stream(Objects.requireNonNull(files)) 38 | .filter(File::isDirectory) 39 | .forEach(supplyDir -> { 40 | try { 41 | SupplyConfig supplyConfig = new SupplyConfig(supplyDir.getName(), supplyDir); 42 | SUPPLY_CONFIG_MAP.put(supplyDir.getName(), supplyConfig); 43 | count.incrementAndGet(); 44 | } catch (SupplyConfigLoadException e) { 45 | GUN_WAR.getLogger().error("SupplyConfig 加载错误!", e); 46 | } 47 | }); 48 | GUN_WAR.getLogger().info("已成功加载" + count + "个商店配置"); 49 | if (GunWar.debug) { 50 | GUN_WAR.getLogger().info("[debug] " + SUPPLY_CONFIG_MAP); 51 | } 52 | } 53 | 54 | public static void clear() { 55 | SUPPLY_CONFIG_MAP.clear(); 56 | } 57 | 58 | public static SupplyConfig getSupplyConfig(String supply) { 59 | return SUPPLY_CONFIG_MAP.get(supply); 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/update/ConfigUpdateUtils.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils.update; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.nukkit.utils.Config; 5 | 6 | import java.io.File; 7 | import java.util.LinkedHashMap; 8 | 9 | /** 10 | * @author LT_Name 11 | */ 12 | public class ConfigUpdateUtils { 13 | 14 | public static void updateConfig(GunWar gunWar) { 15 | updateLanguageFile(gunWar); 16 | } 17 | 18 | private static void updateLanguageFile(GunWar gunWar) { 19 | for (String langName : gunWar.getSupportList()) { 20 | File languageFile = new File(gunWar.getDataFolder() + "/Language/" + langName + ".yml"); 21 | if (languageFile.exists()) { 22 | File newFile = new File(gunWar.getDataFolder() + "/Language/" + langName + "_customize.yml"); 23 | if (newFile.exists()) { 24 | newFile.delete(); 25 | } 26 | languageFile.renameTo(new File(gunWar.getDataFolder() + "/Language/" + langName + "_customize.yml")); 27 | } 28 | } 29 | } 30 | 31 | // 需要在NsGB加载后检查,放到onEnable里 32 | public static void checkFapNsGB(GunWar gunWar) { 33 | try { 34 | Class.forName("cn.nsgamebase.NsGameBaseMain"); 35 | 36 | Config config = gunWar.getConfig(); 37 | 38 | LinkedHashMap fapWinIntegral = new LinkedHashMap<>(); 39 | fapWinIntegral.put("money", 10); 40 | fapWinIntegral.put("exp", 10); 41 | fapWinIntegral.put("maxMultiplier", 1); 42 | 43 | LinkedHashMap fapLoseIntegral = new LinkedHashMap<>(); 44 | fapLoseIntegral.put("money", 5); 45 | fapLoseIntegral.put("exp", 5); 46 | fapLoseIntegral.put("maxMultiplier", 1); 47 | 48 | boolean needSave = false; 49 | if (!config.exists("fapWinIntegral")) { 50 | config.set("fapWinIntegral", fapWinIntegral); 51 | needSave = true; 52 | } 53 | if (!config.exists("fapLoseIntegral")) { 54 | config.set("fapLoseIntegral", fapLoseIntegral); 55 | needSave = true; 56 | } 57 | 58 | if (needSave) { 59 | config.save(); 60 | } 61 | } catch (Exception ignored) { 62 | 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/tasks/GunReloadTask.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.tasks; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.lanink.gunwar.item.ItemManage; 5 | import cn.lanink.gunwar.item.weapon.GunWeapon; 6 | import cn.lanink.gunwar.utils.Tools; 7 | import cn.nukkit.Player; 8 | import cn.nukkit.scheduler.PluginTask; 9 | 10 | /** 11 | * @author lt_name 12 | */ 13 | public class GunReloadTask extends PluginTask { 14 | 15 | private final Player player; 16 | private final GunWeapon gunWeapon; 17 | private final float base; 18 | private final int initialQuantity; 19 | private float bulletsFloat; 20 | 21 | public GunReloadTask(Player player, GunWeapon gunWeapon, float base) { 22 | super(GunWar.getInstance()); 23 | this.player = player; 24 | this.gunWeapon = gunWeapon; 25 | this.base = base; 26 | this.initialQuantity = gunWeapon.getMagazine(player); 27 | this.bulletsFloat = this.initialQuantity; 28 | } 29 | 30 | @Override 31 | public void onRun(int i) { 32 | if (this.bulletsFloat >= this.gunWeapon.getMaxMagazine() || !this.player.isOnline()) { 33 | this.cancel(); 34 | }else { 35 | this.bulletsFloat += this.base; 36 | this.gunWeapon.getMagazineMap().put(this.player, (int) this.bulletsFloat); 37 | if (this.gunWeapon.equals(ItemManage.getGunWeapon(this.player.getInventory().getItemInHand()))) { 38 | this.player.sendTip(Tools.getShowStringMagazine((int) this.bulletsFloat, this.gunWeapon.getMaxMagazine())); 39 | }else { 40 | this.cancel(); 41 | } 42 | } 43 | } 44 | 45 | @Override 46 | public void onCancel() { 47 | //换弹中被打断 48 | if (!this.gunWeapon.isReloadInterrupted() && this.bulletsFloat < this.gunWeapon.getMaxMagazine()) { 49 | this.gunWeapon.getMagazineMap().put(this.player, this.initialQuantity); 50 | this.player.sendTip(Tools.getShowStringMagazine(this.initialQuantity, this.gunWeapon.getMaxMagazine())); 51 | } 52 | //防止溢出 53 | if (this.gunWeapon.getMagazineMap().getOrDefault(this.player, 0) > this.gunWeapon.getMaxMagazine()) { 54 | this.gunWeapon.getMagazineMap().put(this.player, this.gunWeapon.getMaxMagazine()); 55 | } 56 | this.gunWeapon.getReloadTask().remove(player); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/tasks/game/ctf/FlagPickupCheckTask.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.tasks.game.ctf; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.lanink.gunwar.entity.flag.EntityFlag; 5 | import cn.lanink.gunwar.room.capturetheflag.CTFModeRoom; 6 | import cn.nukkit.level.Sound; 7 | import cn.nukkit.scheduler.PluginTask; 8 | 9 | /** 10 | * @author lt_name 11 | */ 12 | public class FlagPickupCheckTask extends PluginTask { 13 | 14 | private int time; 15 | private final CTFModeRoom room; 16 | private final EntityFlag entityFlag; 17 | private final int team; 18 | 19 | public FlagPickupCheckTask(GunWar owner, CTFModeRoom room, EntityFlag entityFlag) { 20 | super(owner); 21 | this.time = 10; 22 | this.room = room; 23 | this.entityFlag = entityFlag; 24 | entityFlag.setNameTagVisible(true); 25 | entityFlag.setNameTagAlwaysVisible(true); 26 | this.team = entityFlag.namedTag.getInt("GunWarTeam"); 27 | } 28 | 29 | @Override 30 | public void onRun(int i) { 31 | if (time <= 0) { 32 | //在传送前位置播放声音 33 | this.entityFlag.getLevel().addSound(this.entityFlag, Sound.MOB_ENDERMEN_PORTAL); 34 | switch (this.team) { 35 | case 11: 36 | this.entityFlag.teleport(this.room.getRedSpawn().add(0, 0.3, 0)); 37 | break; 38 | case 12: 39 | this.entityFlag.teleport(this.room.getBlueSpawn().add(0, 0.3, 0)); 40 | break; 41 | default: 42 | this.entityFlag.close(); 43 | break; 44 | } 45 | //在传送后位置播放声音 46 | this.entityFlag.getLevel().addSound(this.entityFlag, Sound.MOB_ENDERMEN_PORTAL); 47 | this.cancel(); 48 | return; 49 | } 50 | this.entityFlag.setNameTag("§e" + this.time); 51 | if (this.team == 11 && this.room.haveRedFlag != null) { 52 | this.cancel(); 53 | }else if (this.team == 12 && this.room.haveBlueFlag != null) { 54 | this.cancel(); 55 | } 56 | this.time--; 57 | } 58 | 59 | @Override 60 | public void onCancel() { 61 | this.entityFlag.setNameTag(""); 62 | this.entityFlag.setNameTagVisible(false); 63 | this.entityFlag.setNameTagAlwaysVisible(false); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/adminsub/SetRoom.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command.adminsub; 2 | 3 | import cn.lanink.gunwar.command.base.BaseSubCommand; 4 | import cn.lanink.gunwar.gui.GuiCreate; 5 | import cn.lanink.gunwar.tasks.adminroom.SetRoomTask; 6 | import cn.nukkit.Player; 7 | import cn.nukkit.Server; 8 | import cn.nukkit.command.CommandSender; 9 | import cn.nukkit.command.data.CommandParamType; 10 | import cn.nukkit.command.data.CommandParameter; 11 | import cn.nukkit.level.Level; 12 | 13 | /** 14 | * @author lt_name 15 | */ 16 | public class SetRoom extends BaseSubCommand { 17 | 18 | public SetRoom(String name) { 19 | super(name); 20 | } 21 | 22 | @Override 23 | public boolean canUser(CommandSender sender) { 24 | return sender.isPlayer() && sender.isOp(); 25 | } 26 | 27 | @Override 28 | public String[] getAliases() { 29 | return new String[0]; 30 | } 31 | 32 | @Override 33 | public boolean execute(CommandSender sender, String label, String[] args) { 34 | Player player = (Player) sender; 35 | if (this.gunWar.setRoomTask.containsKey(player)) { 36 | this.gunWar.setRoomTask.get(player).cancel(); 37 | }else { 38 | if (args.length < 2) { 39 | GuiCreate.sendSetRoomMenu(player); 40 | }else { 41 | if (this.gunWar.getRoomConfigs().containsKey(args[1])) { 42 | Level level = Server.getInstance().getLevelByName(args[1]); 43 | if (player.getLevel() != level) { 44 | player.teleport(level.getSafeSpawn()); 45 | } 46 | SetRoomTask task = new SetRoomTask(this.gunWar, player, level); 47 | this.gunWar.setRoomTask.put(player, task); 48 | Server.getInstance().getScheduler().scheduleRepeatingTask(this.gunWar, task, 10); 49 | sender.sendMessage(this.language.translateString("admin_setRoom_start", args[1])); 50 | }else { 51 | sender.sendMessage(this.language.translateString("admin_setRoom_noExist")); 52 | } 53 | } 54 | } 55 | return true; 56 | } 57 | 58 | @Override 59 | public CommandParameter[] getParameters() { 60 | return new CommandParameter[]{ new CommandParameter("roomName", CommandParamType.TEXT, false) }; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/room/base/IntegralConfig.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.room.base; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.nukkit.utils.Config; 5 | import lombok.Getter; 6 | import lombok.NonNull; 7 | 8 | import java.util.EnumMap; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | /** 13 | * 积分配置(商店用) 14 | * 15 | * @author LT_Name 16 | */ 17 | public class IntegralConfig { 18 | 19 | @Getter 20 | private final static EnumMap INTEGER_ENUM_MAP = new EnumMap<>(IntegralType.class); 21 | 22 | private IntegralConfig() { 23 | throw new IllegalStateException("Utility class"); 24 | } 25 | 26 | public static void init(Config config) { 27 | Map integralMap = new HashMap<>(); 28 | for (Map.Entry entry : (config.get("integral", new HashMap())).entrySet()) { 29 | integralMap.put(entry.getKey().toUpperCase(), entry.getValue()); //key全部转换为大写 30 | } 31 | for (IntegralType integralType : IntegralType.values()) { 32 | if (integralType == IntegralType.CUSTOM) { 33 | continue; 34 | } 35 | INTEGER_ENUM_MAP.put(integralType, (Integer) integralMap.getOrDefault(integralType.name(), 0)); 36 | } 37 | if (GunWar.debug) { 38 | GunWar.getInstance().getLogger().info("积分配置:" + INTEGER_ENUM_MAP); 39 | } 40 | } 41 | 42 | public static int getIntegral(@NonNull IntegralType integralType) { 43 | return INTEGER_ENUM_MAP.getOrDefault(integralType, 0); 44 | } 45 | 46 | public enum IntegralType { 47 | 48 | /** 49 | * 自定义 (通用) 50 | */ 51 | CUSTOM, 52 | 53 | /** 54 | * 游戏开始时玩家基础积分 55 | */ 56 | START_BASE_INTEGRAL, 57 | 58 | /** 59 | * 击杀敌人 60 | */ 61 | KILL_SCORE, 62 | 63 | /** 64 | * 击杀队友 65 | */ 66 | KILL_TEAM_SCORE, 67 | 68 | /** 69 | * 安放炸弹 (仅爆破模式) 70 | */ 71 | BOMB_SCORE, 72 | 73 | /** 74 | * 拆除炸弹 (仅爆破模式) 75 | */ 76 | DESTROY_SCORE, 77 | 78 | /** 79 | * 运回旗帜得分 (仅夺旗模式) 80 | */ 81 | FLAG_GET_SCORE, 82 | 83 | /** 84 | * 回合胜利 85 | */ 86 | ROUND_WIN_SCORE, 87 | 88 | /** 89 | * 回合失败 90 | */ 91 | ROUND_LOSE_SCORE 92 | 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/ItemKillMessageUtils.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.nukkit.item.Item; 5 | import cn.nukkit.utils.Config; 6 | import com.google.common.cache.Cache; 7 | import com.google.common.cache.CacheBuilder; 8 | import lombok.Data; 9 | 10 | import java.util.HashMap; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | /** 14 | * @author LT_Name 15 | */ 16 | public class ItemKillMessageUtils { 17 | 18 | private static final HashMap ITEM_KILL_MESSAGE = new HashMap<>(); 19 | private static final Cache ITEMDATA_CACHE = CacheBuilder.newBuilder().expireAfterAccess(3, TimeUnit.MINUTES).build(); 20 | 21 | 22 | public static void load() { 23 | GunWar.getInstance().saveResource("ItemKillMessage.yml", false); 24 | new Config(GunWar.getInstance().getDataFolder() + "/ItemKillMessage.yml", Config.YAML).getAll().forEach((key, value) -> { 25 | try { 26 | Item item = Item.fromString(key); 27 | if (item.getId() != Item.AIR) { 28 | ITEM_KILL_MESSAGE.put(ItemData.of(item), value.toString()); 29 | } 30 | }catch (Exception e) { 31 | GunWar.getInstance().getLogger().warning("无法加载物品:" + key + " 的击杀信息!此物品可能不存在,请检查物品id!"); 32 | //nkx不支持字符串物品,大部分报错可以忽略 33 | if (GunWar.debug) { 34 | GunWar.getInstance().getLogger().error("读取ItemKillMessage.yml错误:", e); 35 | } 36 | } 37 | }); 38 | } 39 | 40 | public static void clear() { 41 | ITEM_KILL_MESSAGE.clear(); 42 | } 43 | 44 | public static String getKillMessage(Item item) { 45 | return ITEM_KILL_MESSAGE.get(ItemData.of(item)); 46 | } 47 | 48 | @Data 49 | public static class ItemData { 50 | public int id; 51 | public int damage; 52 | public String name; 53 | 54 | private ItemData(Item item) { 55 | this.id = item.getId(); 56 | this.damage = item.getDamage(); 57 | this.name = item.getName(); 58 | } 59 | 60 | public static ItemData of(Item item) { 61 | ItemData itemData = ITEMDATA_CACHE.getIfPresent(item); 62 | if (itemData == null) { 63 | itemData = new ItemData(item); 64 | ITEMDATA_CACHE.put(item, itemData); 65 | } 66 | return itemData; 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/event/GunWarRoomEndEvent.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.event; 2 | 3 | import cn.lanink.gunwar.room.base.BaseRoom; 4 | import cn.lanink.gunwar.room.base.PlayerGameData; 5 | import cn.lanink.gunwar.room.base.Team; 6 | import cn.nukkit.Player; 7 | import cn.nukkit.event.HandlerList; 8 | 9 | import java.util.LinkedList; 10 | import java.util.Map; 11 | 12 | public class GunWarRoomEndEvent extends GunWarRoomEvent { 13 | 14 | private static final HandlerList handlers = new HandlerList(); 15 | private int victory; 16 | 17 | public GunWarRoomEndEvent(BaseRoom room, int victory) { 18 | this.room = room; 19 | this.victory = victory; 20 | } 21 | 22 | public static HandlerList getHandlers() { 23 | return handlers; 24 | } 25 | 26 | public int getVictory() { 27 | return this.victory; 28 | } 29 | 30 | public void setVictory(int victory) { 31 | this.victory = victory; 32 | } 33 | 34 | /** 35 | * 获取胜利玩家 36 | * @return 胜利玩家 37 | */ 38 | public LinkedList getVictoryPlayers() { 39 | LinkedList players = new LinkedList<>(); 40 | for (Map.Entry entry : this.room.getPlayerDataMap().entrySet()) { 41 | if (this.victory == 1) { 42 | if (entry.getValue().getTeam() == Team.RED || entry.getValue().getTeam() == Team.RED_DEATH) { 43 | players.add(entry.getKey()); 44 | } 45 | }else if (this.victory == 2) { 46 | if (entry.getValue().getTeam() == Team.BLUE || entry.getValue().getTeam() == Team.BLUE_DEATH) { 47 | players.add(entry.getKey()); 48 | } 49 | } 50 | } 51 | return players; 52 | } 53 | 54 | /** 55 | * 获取失败玩家 56 | * @return 失败玩家 57 | */ 58 | public LinkedList getDefeatPlayers() { 59 | LinkedList players = new LinkedList<>(); 60 | for (Map.Entry entry : this.room.getPlayerDataMap().entrySet()) { 61 | if (this.victory == 1) { 62 | if (entry.getValue().getTeam() == Team.BLUE || entry.getValue().getTeam() == Team.BLUE_DEATH) { 63 | players.add(entry.getKey()); 64 | } 65 | }else if (this.victory == 2) { 66 | if (entry.getValue().getTeam() == Team.RED || entry.getValue().getTeam() == Team.RED_DEATH) { 67 | players.add(entry.getKey()); 68 | } 69 | } 70 | } 71 | return players; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/adminsub/CreateRoom.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command.adminsub; 2 | 3 | import cn.lanink.gunwar.command.base.BaseSubCommand; 4 | import cn.lanink.gunwar.gui.GuiCreate; 5 | import cn.nukkit.Player; 6 | import cn.nukkit.Server; 7 | import cn.nukkit.command.CommandSender; 8 | import cn.nukkit.command.data.CommandParamType; 9 | import cn.nukkit.command.data.CommandParameter; 10 | import cn.nukkit.level.Level; 11 | 12 | /** 13 | * @author lt_name 14 | */ 15 | public class CreateRoom extends BaseSubCommand { 16 | 17 | public CreateRoom(String name) { 18 | super(name); 19 | } 20 | 21 | @Override 22 | public boolean canUser(CommandSender sender) { 23 | return sender.isPlayer() && sender.isOp(); 24 | } 25 | 26 | @Override 27 | public String[] getAliases() { 28 | return new String[0]; 29 | } 30 | 31 | @Override 32 | public boolean execute(CommandSender sender, String label, String[] args) { 33 | Player player = (Player) sender; 34 | if (args.length < 2) { 35 | GuiCreate.sendCreateRoomMenu(player); 36 | }else { 37 | if (!this.gunWar.getRoomConfigs().containsKey(args[1])) { 38 | Level level = Server.getInstance().getLevelByName(args[1]); 39 | if (level != null) { 40 | if (this.gunWar.setRoomTask.containsKey(player)) { 41 | this.gunWar.setRoomTask.get(player).cancel(); 42 | } 43 | this.gunWar.getRoomConfig(args[1]); 44 | sender.sendMessage(this.language.translateString("admin_createRoom_success", args[1])); 45 | if (player.getLevel() != level) { 46 | player.teleport(level.getSafeSpawn()); 47 | } 48 | Server.getInstance().dispatchCommand(player, 49 | this.gunWar.getCmdAdmin() + " SetRoom " + args[1]); 50 | if (this.gunWar.setRoomTask.containsKey(player)) { 51 | this.gunWar.setRoomTask.get(player).setAutoNext(true); 52 | } 53 | }else { 54 | sender.sendMessage(this.language.translateString("world_doesNotExist", args[1])); 55 | } 56 | }else { 57 | sender.sendMessage(this.language.translateString("admin_createRoom_exist")); 58 | } 59 | } 60 | return true; 61 | } 62 | 63 | @Override 64 | public CommandParameter[] getParameters() { 65 | return new CommandParameter[]{ new CommandParameter("worldName", CommandParamType.TEXT, false) }; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/item/base/BaseItem.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.item.base; 2 | 3 | import cn.lanink.gunwar.item.ItemManage; 4 | import cn.nukkit.item.Item; 5 | import cn.nukkit.nbt.tag.CompoundTag; 6 | import cn.nukkit.utils.Config; 7 | 8 | /** 9 | * @author lt_name 10 | */ 11 | public abstract class BaseItem { 12 | 13 | public static final String GUN_WAR_ITEM_TAG = "GunWarItemTag"; 14 | public static final String GUN_WAR_ITEM_NAME = "GunWarItemName"; 15 | public static final String GUN_WAR_ITEM_TYPE = "GunWarItemType"; 16 | 17 | private final String name; 18 | public final Item item; 19 | private final boolean infiniteDurability; 20 | 21 | public BaseItem(String name, Config config) { 22 | this.name = name; 23 | this.item = Item.fromString(config.getString("id")); 24 | this.item.setCustomName(config.getString("showName", this.item.getName())); 25 | String lore = config.getString("lore"); 26 | if (!lore.trim().isEmpty()) { 27 | this.item.setLore(lore.split("\n")); 28 | } 29 | if (!this.item.hasCompoundTag()) { 30 | this.item.setNamedTag(new CompoundTag()); 31 | } 32 | this.infiniteDurability = config.getBoolean("infiniteDurability", false); 33 | if (this.infiniteDurability) { 34 | this.item.getNamedTag().putByte("Unbreakable", 1); 35 | } 36 | this.item.getNamedTag().putCompound(GUN_WAR_ITEM_TAG, new CompoundTag() 37 | .putString(GUN_WAR_ITEM_NAME, this.name) 38 | .putString(GUN_WAR_ITEM_TYPE, this.getItemType().getStringType())) 39 | .putBoolean("infiniteDurability", this.infiniteDurability); 40 | } 41 | 42 | public abstract ItemManage.ItemType getItemType(); 43 | 44 | /** 45 | * @return 名称 46 | */ 47 | public String getName() { 48 | return this.name; 49 | } 50 | 51 | /** 52 | * @return 显示名称 53 | */ 54 | public String getShowName() { 55 | return this.item.getCustomName(); 56 | } 57 | 58 | /** 59 | * @return 无限耐久 60 | */ 61 | public boolean isInfiniteDurability() { 62 | return infiniteDurability; 63 | } 64 | 65 | /** 66 | * @return 物品 67 | */ 68 | public Item getItem() { 69 | return this.item.clone(); 70 | } 71 | 72 | public CompoundTag getCompoundTag() { 73 | return this.item.getNamedTag().getCompound(GUN_WAR_ITEM_TAG); 74 | } 75 | 76 | public void setCompoundTag(CompoundTag compoundTag) { 77 | CompoundTag tag = this.item.getNamedTag(); 78 | tag.putCompound(GUN_WAR_ITEM_TAG, compoundTag); 79 | this.item.setCompoundTag(tag); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/gamerecord/GameRecord.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils.gamerecord; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.nukkit.Player; 5 | import cn.nukkit.utils.Config; 6 | 7 | import java.util.*; 8 | 9 | /** 10 | * @author lt_name 11 | */ 12 | public class GameRecord { 13 | 14 | public static LinkedHashMap getRankingList(RecordType recordType) { 15 | Config config = GunWar.getInstance().getGameRecord(); 16 | Map map = config.getAll(); 17 | HashMap list = new HashMap<>(); 18 | for (Map.Entry entry : map.entrySet()) { 19 | list.put(entry.getKey(), getPlayerRecord(entry.getKey()).getOrDefault(recordType.getName(), 0)); 20 | } 21 | return getRankingList(list); 22 | } 23 | 24 | public static HashMap getPlayerRecord(Player player) { 25 | return getPlayerRecord(player.getName()); 26 | } 27 | 28 | public static HashMap getPlayerRecord(String player) { 29 | return GunWar.getInstance().getGameRecord().get(player, new HashMap<>()); 30 | } 31 | 32 | public static void addPlayerRecord(Player player, RecordType recordType) { 33 | addPlayerRecord(player.getName(), recordType); 34 | } 35 | 36 | public static void addPlayerRecord(String player, RecordType recordType) { 37 | Config config = GunWar.getInstance().getGameRecord(); 38 | HashMap record = getPlayerRecord(player); 39 | record.put(recordType.getName(), getPlayerRecord(player, recordType) + 1); 40 | config.set(player, record); 41 | config.save(); 42 | } 43 | 44 | public static int getPlayerRecord(Player player, RecordType recordType) { 45 | return getPlayerRecord(player.getName(), recordType); 46 | } 47 | 48 | public static int getPlayerRecord(String player, RecordType recordType) { 49 | return getPlayerRecord(player).getOrDefault(recordType.getName(), 0); 50 | } 51 | 52 | /** 53 | * 排行榜 54 | * 55 | * @param map 数据 56 | * @return 排行后的数据 57 | */ 58 | public static LinkedHashMap getRankingList(Map map) { 59 | LinkedHashMap map1 = new LinkedHashMap<>(); 60 | List> list = new LinkedList<>(map.entrySet()); 61 | list.sort((o1, o2) -> o2.getValue() - o1.getValue()); 62 | for (Map.Entry entry : list) { 63 | map1.put(entry.getKey(), entry.getValue()); 64 | } 65 | /* map1 = map.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) 66 | .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, 67 | (oldValue, newValue) -> oldValue, LinkedHashMap::new));*/ 68 | return map1; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/tasks/game/ScoreBoardTask.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.tasks.game; 2 | 3 | import cn.lanink.gamecore.room.IRoomStatus; 4 | import cn.lanink.gamecore.utils.Language; 5 | import cn.lanink.gunwar.GunWar; 6 | import cn.lanink.gunwar.room.base.BaseRoom; 7 | import cn.lanink.gunwar.room.base.PlayerGameData; 8 | import cn.lanink.gunwar.room.base.Team; 9 | import cn.lanink.gunwar.room.freeforall.FreeForAllModeRoom; 10 | import cn.lanink.gunwar.utils.Tools; 11 | import cn.nukkit.Player; 12 | import cn.nukkit.scheduler.PluginTask; 13 | 14 | import java.util.LinkedList; 15 | 16 | 17 | /** 18 | * 信息显示 19 | */ 20 | public class ScoreBoardTask extends PluginTask { 21 | 22 | private final Language language; 23 | private final BaseRoom room; 24 | 25 | public ScoreBoardTask(GunWar owner, BaseRoom room) { 26 | super(owner); 27 | this.language = owner.getLanguage(); 28 | this.room = room; 29 | } 30 | 31 | @Override 32 | public void onRun(int i) { 33 | if (this.room.getStatus() != IRoomStatus.ROOM_STATUS_GAME) { 34 | this.cancel(); 35 | return; 36 | } 37 | if (!this.room.getPlayerDataMap().isEmpty()) { 38 | int red = 0; 39 | int blue = 0; 40 | if (this.room instanceof FreeForAllModeRoom) { 41 | red = this.room.getPlayerDataMap().size(); 42 | }else { 43 | for (PlayerGameData gameData : this.room.getPlayerDataMap().values()) { 44 | if (gameData.getTeam() == Team.RED) { 45 | red++; 46 | } else if (gameData.getTeam() == Team.BLUE) { 47 | blue++; 48 | } 49 | } 50 | } 51 | for (Player player : this.room.getPlayerDataMap().keySet()) { 52 | LinkedList ms = new LinkedList<>(); 53 | for (String string : this.language.translateString("gameTimeScoreBoard").split("\n")) { 54 | ms.add(string.replace("%gameMode%", Tools.getShowGameMode(this.room.getGameMode())) 55 | .replace("%team%", this.room.getPlayerTeamAccurate(player).getShowName()) 56 | .replace("%health%", String.format("%.1f", room.getPlayerHealth(player))) 57 | .replace("%time%", String.valueOf(room.gameTime)) 58 | .replace("%red%", String.valueOf(red)) 59 | .replace("%blue%", String.valueOf(blue)) 60 | .replace("%redRound%", String.valueOf(room.redScore)) 61 | .replace("%blueRound%", String.valueOf(room.blueScore)) 62 | .replace("%integral%", String.valueOf(room.getPlayerIntegral(player)))); 63 | } 64 | owner.getScoreboard().showScoreboard(player, this.language.translateString("scoreBoardTitle"), ms); 65 | } 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/tasks/game/conquest/FlagSpawnCheckTask.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.tasks.game.conquest; 2 | 3 | import cn.lanink.gamecore.room.IRoomStatus; 4 | import cn.lanink.gunwar.GunWar; 5 | import cn.lanink.gunwar.entity.flag.EntityLongFlag; 6 | import cn.lanink.gunwar.room.base.Team; 7 | import cn.lanink.gunwar.room.conquest.ConquestModeRoom; 8 | import cn.lanink.gunwar.utils.FlagSkinType; 9 | import cn.nukkit.entity.data.Skin; 10 | import cn.nukkit.level.Position; 11 | import cn.nukkit.math.Vector3; 12 | import cn.nukkit.nbt.tag.CompoundTag; 13 | import cn.nukkit.scheduler.PluginTask; 14 | 15 | /** 16 | * 征服模式旗帜实体存活检查 17 | * 18 | * @author LT_Name 19 | */ 20 | public class FlagSpawnCheckTask extends PluginTask { 21 | 22 | private final ConquestModeRoom room; 23 | 24 | public FlagSpawnCheckTask(GunWar owner, ConquestModeRoom room) { 25 | super(owner); 26 | this.room = room; 27 | } 28 | 29 | @Override 30 | public void onRun(int i) { 31 | if (this.room.getStatus() != IRoomStatus.ROOM_STATUS_GAME) { 32 | this.cancel(); 33 | return; 34 | } 35 | 36 | this.checkAndSpawnFlag(1); 37 | this.checkAndSpawnFlag(2); 38 | this.checkAndSpawnFlag(3); 39 | } 40 | 41 | private void checkAndSpawnFlag(int i) { 42 | EntityLongFlag entityLongFlag = null; 43 | Vector3 vector3 = null; 44 | switch (i) { 45 | case 1: 46 | entityLongFlag = this.room.flagA; 47 | vector3 = this.room.getConquestPointA(); 48 | break; 49 | case 2: 50 | entityLongFlag = this.room.flagB; 51 | vector3 = this.room.getConquestPointB(); 52 | break; 53 | case 3: 54 | entityLongFlag = this.room.flagC; 55 | vector3 = this.room.getConquestPointC(); 56 | break; 57 | } 58 | if (vector3 == null) { 59 | return; 60 | } 61 | if (entityLongFlag == null || entityLongFlag.isClosed()) { 62 | Skin skin = GunWar.getInstance().getFlagSkin(FlagSkinType.LONG_FLAGPOLE); 63 | Position position = Position.fromObject(vector3, this.room.getLevel()); 64 | CompoundTag tag = EntityLongFlag.getDefaultNBT(position); 65 | tag.putCompound("Skin", new CompoundTag() 66 | .putByteArray("Data", skin.getSkinData().data) 67 | .putString("ModelId", skin.getSkinId())); 68 | entityLongFlag = new EntityLongFlag(position.getChunk(), tag, Team.NULL); 69 | entityLongFlag.setSkin(skin); 70 | entityLongFlag.spawnToAll(); 71 | switch (i) { 72 | case 1: 73 | this.room.flagA = entityLongFlag; 74 | break; 75 | case 2: 76 | this.room.flagB = entityLongFlag; 77 | break; 78 | case 3: 79 | this.room.flagC = entityLongFlag; 80 | break; 81 | } 82 | } 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/listener/defaults/DebugMessageListener.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.listener.defaults; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.lanink.gunwar.entity.flag.EntityLongFlag; 5 | import cn.lanink.gunwar.entity.tower.EntityCrossbowTower; 6 | import cn.lanink.gunwar.room.base.Team; 7 | import cn.lanink.gunwar.utils.FlagSkinType; 8 | import cn.nukkit.Player; 9 | import cn.nukkit.entity.Entity; 10 | import cn.nukkit.entity.data.Skin; 11 | import cn.nukkit.event.EventHandler; 12 | import cn.nukkit.event.EventPriority; 13 | import cn.nukkit.event.Listener; 14 | import cn.nukkit.event.player.PlayerChatEvent; 15 | import cn.nukkit.nbt.tag.CompoundTag; 16 | 17 | /** 18 | * @author LT_Name 19 | */ 20 | public class DebugMessageListener implements Listener { 21 | 22 | private final GunWar gunWar; 23 | 24 | public DebugMessageListener(GunWar gunWar) { 25 | this.gunWar = gunWar; 26 | } 27 | 28 | @EventHandler(priority = EventPriority.LOWEST) 29 | public void onChat(PlayerChatEvent event) { 30 | Player player = event.getPlayer(); 31 | String message = event.getMessage(); 32 | if (player == null || !player.isOp() || message == null) { 33 | return; 34 | } 35 | 36 | if ("LongFlagSpawn".equalsIgnoreCase(message)) { 37 | Skin skin = this.gunWar.getFlagSkin(FlagSkinType.LONG_FLAGPOLE); 38 | CompoundTag tag = EntityLongFlag.getDefaultNBT(player); 39 | tag.putCompound("Skin", new CompoundTag() 40 | .putByteArray("Data", skin.getSkinData().data) 41 | .putString("ModelId", skin.getSkinId())); 42 | EntityLongFlag flag = new EntityLongFlag(player.getChunk(), tag, Team.RED); 43 | flag.setSkin(skin); 44 | flag.spawnToAll(); 45 | } else if ("LongFlag+".equalsIgnoreCase(message)) { 46 | for (Entity entity : player.getLevel().getEntities()) { 47 | if (entity instanceof EntityLongFlag) { 48 | EntityLongFlag longFlag = (EntityLongFlag) entity; 49 | longFlag.setFlagHeight(longFlag.getFlagHeight() + 10); 50 | this.gunWar.getLogger().info("[debug] LongFlag Now Height" + longFlag.getFlagHeight()); 51 | } 52 | } 53 | } else if ("LongFlag-".equalsIgnoreCase(message)) { 54 | for (Entity entity : player.getLevel().getEntities()) { 55 | if (entity instanceof EntityLongFlag) { 56 | EntityLongFlag longFlag = (EntityLongFlag) entity; 57 | longFlag.setFlagHeight(longFlag.getFlagHeight() - 10); 58 | this.gunWar.getLogger().info("[debug] LongFlag Now Height" + longFlag.getFlagHeight()); 59 | } 60 | } 61 | } else if ("CrossbowTowerSpawn".equalsIgnoreCase(message)) { 62 | EntityCrossbowTower crossbowTower = new EntityCrossbowTower(this.gunWar.getGameRoomManager().getCanJoinGameRoom(), Team.RED, player.getChunk(), EntityCrossbowTower.getDefaultNBT(player)); 63 | crossbowTower.spawnToAll(); 64 | crossbowTower.addTarget(player); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/room/base/BaseRespawnModeRoom.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.room.base; 2 | 3 | import cn.lanink.gamecore.utils.exception.RoomLoadException; 4 | import cn.lanink.gunwar.utils.Tools; 5 | import cn.nukkit.Player; 6 | import cn.nukkit.entity.Entity; 7 | import cn.nukkit.level.Level; 8 | import cn.nukkit.level.Sound; 9 | import cn.nukkit.utils.Config; 10 | import lombok.Getter; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | * 单回合可重生房间类型 18 | * 19 | * @author LT_Name 20 | */ 21 | public abstract class BaseRespawnModeRoom extends BaseRoom { 22 | 23 | //玩家复活所需时间 24 | @Getter 25 | protected int respawnNeedTime; 26 | 27 | /** 28 | * 玩家重生时间 29 | */ 30 | protected final HashMap playerRespawnTime = new HashMap<>(); 31 | 32 | /** 33 | * 初始化 34 | * 35 | * @param level 游戏世界 36 | * @param config 配置文件 37 | */ 38 | public BaseRespawnModeRoom(@NotNull Level level, @NotNull Config config) throws RoomLoadException { 39 | super(level, config); 40 | 41 | this.respawnNeedTime = config.getInt("respawn-need-time", 20); 42 | } 43 | 44 | @Override 45 | public void saveConfig() { 46 | super.saveConfig(); 47 | 48 | this.config.set("respawn-need-time", this.respawnNeedTime); 49 | 50 | this.config.save(); 51 | } 52 | 53 | @Override 54 | protected void initData() { 55 | super.initData(); 56 | 57 | if (this.playerRespawnTime != null) { 58 | this.playerRespawnTime.clear(); 59 | } 60 | } 61 | 62 | @Override 63 | public void timeTask() { 64 | super.timeTask(); 65 | 66 | //玩家复活计算 67 | for (Map.Entry entry : this.getPlayerRespawnTime().entrySet()) { 68 | if (entry.getValue() > 0) { 69 | entry.setValue(entry.getValue() - 1); 70 | if (entry.getValue() == 0) { 71 | this.playerRespawn(entry.getKey()); 72 | }else if (entry.getValue() <= 5) { 73 | Tools.playSound(entry.getKey(), Sound.RANDOM_CLICK); 74 | } 75 | } 76 | } 77 | } 78 | 79 | @Override 80 | public void quitRoom(Player player) { 81 | super.quitRoom(player); 82 | this.playerRespawnTime.remove(player); 83 | } 84 | 85 | /** 86 | * 获取玩家重生剩余时间 87 | * @return 玩家重生剩余时间Map 88 | */ 89 | public HashMap getPlayerRespawnTime() { 90 | return this.playerRespawnTime; 91 | } 92 | 93 | /** 94 | * 获取玩家重生剩余时间 95 | * 96 | * @param player 玩家 97 | * @return 重生剩余时间 98 | */ 99 | public int getPlayerRespawnTime(@NotNull Player player) { 100 | return this.playerRespawnTime.getOrDefault(player, 0); 101 | } 102 | 103 | @Override 104 | public void playerDeath(Player player, Entity damager, String killMessage) { 105 | super.playerDeath(player, damager, killMessage); 106 | this.getPlayerRespawnTime().put(player, this.respawnNeedTime); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/tasks/game/ShowHealthTask.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.tasks.game; 2 | 3 | import cn.lanink.gamecore.room.IRoomStatus; 4 | import cn.lanink.gamecore.utils.Language; 5 | import cn.lanink.gunwar.GunWar; 6 | import cn.lanink.gunwar.room.base.BaseRespawnModeRoom; 7 | import cn.lanink.gunwar.room.base.BaseRoom; 8 | import cn.lanink.gunwar.room.base.PlayerGameData; 9 | import cn.lanink.gunwar.utils.Tools; 10 | import cn.nukkit.Player; 11 | import cn.nukkit.scheduler.PluginTask; 12 | import cn.nukkit.utils.DummyBossBar; 13 | 14 | import java.util.Map; 15 | import java.util.concurrent.ConcurrentHashMap; 16 | 17 | public class ShowHealthTask extends PluginTask { 18 | 19 | private final Language language; 20 | private final BaseRoom room; 21 | private final ConcurrentHashMap bossBarMap = new ConcurrentHashMap<>(); 22 | 23 | public ShowHealthTask(GunWar owner, BaseRoom room) { 24 | super(owner); 25 | this.language = owner.getLanguage(); 26 | this.room = room; 27 | } 28 | 29 | @Override 30 | public void onRun(int i) { 31 | if (this.room.getStatus() != IRoomStatus.ROOM_STATUS_GAME) { 32 | this.cancel(); 33 | return; 34 | } 35 | for (Map.Entry entry : this.room.getPlayerDataMap().entrySet()) { 36 | Tools.createBossBar(entry.getKey(), this.bossBarMap); 37 | DummyBossBar bossBar = this.bossBarMap.get(entry.getKey()); 38 | switch (entry.getValue().getTeam()) { 39 | case RED_DEATH: 40 | case BLUE_DEATH: 41 | if (this.room instanceof BaseRespawnModeRoom) { 42 | int respawnTime = ((BaseRespawnModeRoom) this.room).getPlayerRespawnTime(entry.getKey()); 43 | bossBar.setText(this.language.translateString("gameTimeRespawnBoosBar", respawnTime)); 44 | bossBar.setLength(100 - (respawnTime / 20F * 100)); 45 | break; 46 | } 47 | default: 48 | float health = room.getPlayerHealth(entry.getKey()); 49 | int maxHealth; 50 | if (this.owner.isEnableAloneHealth()) { 51 | maxHealth = 20; 52 | }else { 53 | maxHealth = entry.getKey().getMaxHealth(); 54 | } 55 | bossBar.setText(this.language.translateString("gameTimeBoosBar", 56 | "§c" + String.format("%.1f", health) + "/" + maxHealth + "§f ")); 57 | bossBar.setLength(health / maxHealth * 100); 58 | break; 59 | } 60 | } 61 | for (Map.Entry entry : this.bossBarMap.entrySet()) { 62 | if (!this.room.isPlaying(entry.getKey())) { 63 | entry.getKey().removeBossBar(entry.getValue().getBossBarId()); 64 | } 65 | } 66 | } 67 | 68 | @Override 69 | public void onCancel() { 70 | for (DummyBossBar bossBar : this.bossBarMap.values()) { 71 | bossBar.getPlayer().removeBossBar(bossBar.getBossBarId()); 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/tasks/game/blasting/DemolitionBombTask.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.tasks.game.blasting; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.lanink.gunwar.room.base.IntegralConfig; 5 | import cn.lanink.gunwar.room.base.Team; 6 | import cn.lanink.gunwar.room.blasting.BlastingModeRoom; 7 | import cn.lanink.gunwar.utils.Tools; 8 | import cn.nukkit.Player; 9 | import cn.nukkit.Server; 10 | import cn.nukkit.math.Vector3; 11 | import cn.nukkit.scheduler.PluginTask; 12 | 13 | import java.util.HashSet; 14 | 15 | /** 16 | * @author lt_name 17 | */ 18 | public class DemolitionBombTask extends PluginTask { 19 | 20 | public static final HashSet DEMOLITION_BOMB_PLAYERS = new HashSet<>(); 21 | private final BlastingModeRoom room; 22 | private final Player player; 23 | private final Vector3 playerPosition; 24 | private final double base; 25 | private double demolitionProgress; 26 | public static final int MAX_DEMOLITION_PROGRESS = 50; 27 | 28 | public DemolitionBombTask(BlastingModeRoom room, Player player, double base) { 29 | super(GunWar.getInstance()); 30 | this.room = room; 31 | this.player = player; 32 | this.playerPosition = player.clone(); 33 | this.base = base; 34 | DEMOLITION_BOMB_PLAYERS.add(player); 35 | } 36 | 37 | @Override 38 | public void onRun(int i) { 39 | this.demolitionProgress += this.base; 40 | if (i%5 == 0) { 41 | this.player.sendTip(Tools.getShowStringProgress((int) this.demolitionProgress, MAX_DEMOLITION_PROGRESS)); 42 | } 43 | if (!DEMOLITION_BOMB_PLAYERS.contains(this.player) || 44 | this.room.getEntityGunWarBomb() == null || 45 | this.room.getEntityGunWarBomb().isClosed() || 46 | this.playerPosition.distance(this.player) > 0.5 || 47 | this.demolitionProgress >= MAX_DEMOLITION_PROGRESS) { 48 | this.cancel(); 49 | } 50 | } 51 | 52 | @Override 53 | public void onCancel() { 54 | Server.getInstance().getScheduler().scheduleTask(this.owner, () -> { 55 | if (this.demolitionProgress >= MAX_DEMOLITION_PROGRESS) { 56 | Tools.sendTitle(this.room, "", 57 | this.owner.getLanguage().translateString("game_blasting_bombHasBeenDismantled")); 58 | this.room.setRoundIsEnd(true); 59 | if (this.room.getEntityGunWarBomb() != null) { 60 | this.room.getEntityGunWarBomb().close(); 61 | } 62 | if (this.room.getEntityGunWarBombBlock() != null) { 63 | this.room.getEntityGunWarBombBlock().close(); 64 | } 65 | Server.getInstance().getScheduler().scheduleDelayedTask(this.owner, () -> this.room.roundEnd(Team.BLUE), 60); 66 | 67 | this.room.addPlayerIntegral(this.player, IntegralConfig.getIntegral(IntegralConfig.IntegralType.DESTROY_SCORE)); 68 | }else { 69 | this.player.sendTitle("", 70 | this.owner.getLanguage().translateString("game_blasting_cancelDemolition")); 71 | this.room.demolitionBombPlayer = null; 72 | } 73 | this.player.sendTip(" "); 74 | DEMOLITION_BOMB_PLAYERS.remove(this.player); 75 | }); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/listener/capturetheflag/CTFDamageListener.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.listener.capturetheflag; 2 | 3 | import cn.lanink.gamecore.listener.BaseGameListener; 4 | import cn.lanink.gamecore.utils.Language; 5 | import cn.lanink.gunwar.GunWar; 6 | import cn.lanink.gunwar.entity.flag.EntityFlag; 7 | import cn.lanink.gunwar.entity.flag.EntityFlagStand; 8 | import cn.lanink.gunwar.room.base.Team; 9 | import cn.lanink.gunwar.room.capturetheflag.CTFModeRoom; 10 | import cn.nukkit.Player; 11 | import cn.nukkit.event.EventHandler; 12 | import cn.nukkit.event.entity.EntityDamageByEntityEvent; 13 | import cn.nukkit.event.entity.EntityDamageEvent; 14 | 15 | /** 16 | * @author lt_name 17 | */ 18 | public class CTFDamageListener extends BaseGameListener { 19 | 20 | /** 21 | * 实体受到另一实体伤害事件 22 | * @param event 事件 23 | */ 24 | @EventHandler 25 | public void onDamageByEntity(EntityDamageByEntityEvent event) { 26 | if (event.getDamager() instanceof Player && !(event.getEntity() instanceof Player)) { 27 | Player damagePlayer = (Player) event.getDamager(); 28 | if (damagePlayer == null) { 29 | return; 30 | } 31 | CTFModeRoom room = this.getListenerRoom(damagePlayer.getLevel()); 32 | if (room == null || !room.isPlaying(damagePlayer)) { 33 | return; 34 | } 35 | if (event.getCause() == EntityDamageEvent.DamageCause.ENTITY_ATTACK && 36 | event.getEntity().distance(damagePlayer) < 3) { 37 | if (event.getEntity() instanceof EntityFlag) { 38 | EntityFlag entityFlag = (EntityFlag) event.getEntity(); 39 | int team = entityFlag.namedTag.getInt("GunWarTeam"); 40 | Language language = GunWar.getInstance().getLanguage(); 41 | if (team == 11 && room.getPlayerTeamAccurate(damagePlayer) == Team.BLUE) { 42 | room.redFlagPickup(damagePlayer); 43 | } else if (team == 12 && room.getPlayerTeamAccurate(damagePlayer) == Team.RED) { 44 | room.blueFlagPickup(damagePlayer); 45 | } 46 | } else if (event.getEntity() instanceof EntityFlagStand) { 47 | EntityFlagStand entityFlagStand = (EntityFlagStand) event.getEntity(); 48 | int team = entityFlagStand.namedTag.getInt("GunWarTeam"); 49 | if ((team == 1 && room.getPlayerTeamAccurate(damagePlayer) == Team.RED) || 50 | (team == 2 && room.getPlayerTeamAccurate(damagePlayer) == Team.BLUE)) { 51 | switch (team) { 52 | case 1: 53 | if (room.haveBlueFlag == damagePlayer) { 54 | room.blueFlagDelivery(damagePlayer); 55 | } 56 | break; 57 | case 2: 58 | if (room.haveRedFlag == damagePlayer) { 59 | room.redFlagDelivery(damagePlayer); 60 | } 61 | break; 62 | default: 63 | break; 64 | } 65 | } 66 | } 67 | } 68 | event.setCancelled(true); 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/entity/bullet/BulletSnowBall.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.entity.bullet; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.lanink.gunwar.item.base.BaseItem; 5 | import cn.nukkit.Player; 6 | import cn.nukkit.Server; 7 | import cn.nukkit.entity.Entity; 8 | import cn.nukkit.entity.projectile.EntitySnowball; 9 | import cn.nukkit.level.ParticleEffect; 10 | import cn.nukkit.level.format.FullChunk; 11 | import cn.nukkit.math.Vector3; 12 | import cn.nukkit.nbt.tag.CompoundTag; 13 | import cn.nukkit.nbt.tag.DoubleTag; 14 | import cn.nukkit.nbt.tag.FloatTag; 15 | import cn.nukkit.nbt.tag.ListTag; 16 | import cn.nukkit.network.protocol.LevelSoundEventPacket; 17 | 18 | /** 19 | * @author lt_name 20 | */ 21 | public class BulletSnowBall extends EntitySnowball implements IBullet { 22 | 23 | protected float gravity = 0.03F; 24 | protected ParticleEffect particleEffect; 25 | 26 | private BulletSnowBall(FullChunk chunk, CompoundTag nbt, Entity shootingEntity) { 27 | super(chunk, nbt, shootingEntity); 28 | } 29 | 30 | public static void launch(Player player, 31 | Vector3 directionVector, 32 | float gravity, 33 | float motionMultiply, 34 | ParticleEffect particleEffect, 35 | CompoundTag compoundTag) { 36 | CompoundTag nbt = (new CompoundTag()) 37 | .putList((new ListTag<>("Pos")) 38 | .add(new DoubleTag("", player.x)) 39 | .add(new DoubleTag("", player.y + (double)player.getEyeHeight() - 0.30000000149011613D)) 40 | .add(new DoubleTag("", player.z))) 41 | .putList((new ListTag<>("Motion")) 42 | .add(new DoubleTag("", directionVector.x)) 43 | .add(new DoubleTag("", directionVector.y)) 44 | .add(new DoubleTag("", directionVector.z))) 45 | .putList((new ListTag<>("Rotation")) 46 | .add(new FloatTag("", (float)player.yaw)) 47 | .add(new FloatTag("", (float)player.pitch))); 48 | nbt.putCompound(BaseItem.GUN_WAR_ITEM_TAG, compoundTag); 49 | BulletSnowBall bulletSnowBall = new BulletSnowBall(player.getChunk(), nbt, player); 50 | bulletSnowBall.setGravity(gravity); 51 | bulletSnowBall.setParticleEffect(particleEffect); 52 | bulletSnowBall.setMotion(bulletSnowBall.getMotion().multiply(motionMultiply)); 53 | for (Player p : player.getLevel().getChunkPlayers(player.getFloorX() >> 4, player.getFloorZ() >> 4).values()) { 54 | if (p != player) { 55 | bulletSnowBall.spawnTo(p); 56 | } 57 | } 58 | Server.getInstance().getScheduler().scheduleDelayedTask(GunWar.getInstance(), () -> { 59 | if (!bulletSnowBall.isClosed()) { 60 | bulletSnowBall.spawnTo(player); 61 | } 62 | }, 10); 63 | player.getLevel().addLevelSoundEvent(player, LevelSoundEventPacket.SOUND_BOW); 64 | } 65 | 66 | @Override 67 | public void setGravity(float gravity) { 68 | this.gravity = gravity; 69 | } 70 | 71 | @Override 72 | public float getGravity() { 73 | return this.gravity; 74 | } 75 | 76 | @Override 77 | public void setParticleEffect(ParticleEffect particleEffect) { 78 | this.particleEffect = particleEffect; 79 | } 80 | 81 | @Override 82 | public boolean onUpdate(int currentTick) { 83 | boolean onUpdate = super.onUpdate(currentTick); 84 | if (this.particleEffect != null && !this.closed && 85 | !this.onGround && !this.hadCollision && currentTick %5 == 0) { 86 | this.level.addParticleEffect(this, this.particleEffect); 87 | } 88 | return onUpdate; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/base/BaseCommand.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command.base; 2 | 3 | import cn.lanink.gamecore.utils.Language; 4 | import cn.lanink.gunwar.GunWar; 5 | import cn.nukkit.command.Command; 6 | import cn.nukkit.command.CommandSender; 7 | import cn.nukkit.command.data.CommandParameter; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.LinkedList; 12 | import java.util.concurrent.ConcurrentHashMap; 13 | 14 | /** 15 | * @author SmallasWater 16 | */ 17 | abstract public class BaseCommand extends Command { 18 | 19 | private final ArrayList subCommand = new ArrayList<>(); 20 | private final ConcurrentHashMap subCommands = new ConcurrentHashMap<>(); 21 | protected GunWar gunWar = GunWar.getInstance(); 22 | protected Language language = gunWar.getLanguage(); 23 | 24 | public BaseCommand(String name, String description) { 25 | super(name.toLowerCase(), description); 26 | } 27 | 28 | /** 29 | * 判断权限 30 | * @param sender 玩家 31 | * @return 是否拥有权限 32 | */ 33 | public boolean hasPermission(CommandSender sender) { 34 | return sender.hasPermission(this.getPermission()); 35 | } 36 | 37 | @Override 38 | public boolean execute(CommandSender sender, String s, String[] args) { 39 | if(hasPermission(sender)) { 40 | if(args.length > 0) { 41 | String subCommand = args[0].toLowerCase(); 42 | if (subCommands.containsKey(subCommand)) { 43 | BaseSubCommand command = this.subCommand.get(this.subCommands.get(subCommand)); 44 | if (command.canUser(sender)) { 45 | return command.execute(sender, s, args); 46 | }else if (sender.isPlayer()) { 47 | sender.sendMessage(this.language.translateString("noPermission")); 48 | }else { 49 | sender.sendMessage(this.language.translateString("useCmdInCon")); 50 | return true; 51 | } 52 | }else { 53 | this.sendHelp(sender); 54 | return true; 55 | } 56 | }else { 57 | if (sender.isPlayer()) { 58 | this.sendUI(sender); 59 | }else { 60 | this.sendHelp(sender); 61 | } 62 | return true; 63 | } 64 | } 65 | sender.sendMessage(this.language.translateString("noPermission")); 66 | return true; 67 | } 68 | 69 | /** 70 | * 发送帮助 71 | * @param sender 玩家 72 | * */ 73 | public abstract void sendHelp(CommandSender sender); 74 | 75 | /** 76 | * 发送UI 77 | * @param sender 玩家 78 | */ 79 | public abstract void sendUI(CommandSender sender); 80 | 81 | protected void addSubCommand(BaseSubCommand cmd) { 82 | this.subCommand.add(cmd); 83 | int commandId = (this.subCommand.size()) - 1; 84 | this.subCommands.put(cmd.getName().toLowerCase(), commandId); 85 | for (String alias : cmd.getAliases()) { 86 | this.subCommands.put(alias.toLowerCase(), commandId); 87 | } 88 | } 89 | 90 | protected void loadCommandBase(){ 91 | this.commandParameters.clear(); 92 | for(BaseSubCommand subCommand : this.subCommand){ 93 | LinkedList parameters = new LinkedList<>(); 94 | parameters.add(new CommandParameter(subCommand.getName(), new String[]{subCommand.getName()})); 95 | parameters.addAll(Arrays.asList(subCommand.getParameters())); 96 | this.commandParameters.put(subCommand.getName(),parameters.toArray(new CommandParameter[0])); 97 | } 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/entity/tower/EntityBaseTower.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.entity.tower; 2 | 3 | import cn.lanink.gunwar.entity.bullet.BulletArrow; 4 | import cn.lanink.gunwar.room.base.BaseRoom; 5 | import cn.lanink.gunwar.room.base.Team; 6 | import cn.nukkit.entity.EntityCreature; 7 | import cn.nukkit.entity.EntityHuman; 8 | import cn.nukkit.level.format.FullChunk; 9 | import cn.nukkit.math.Vector3; 10 | import cn.nukkit.nbt.tag.CompoundTag; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.Comparator; 14 | import java.util.PriorityQueue; 15 | 16 | /** 17 | * @author LT_Name 18 | */ 19 | public class EntityBaseTower extends EntityHuman { 20 | 21 | private TowerDefinition towerDefinition = TowerDefinition.DEFAULT; 22 | private final BaseRoom room; 23 | private Team team; 24 | 25 | private final PriorityQueue targetQueue = new PriorityQueue<>(Comparator.comparingDouble(o -> o.distance(this))); 26 | private EntityCreature nowTarget; 27 | 28 | private int attackTick; 29 | 30 | public EntityBaseTower(@NotNull BaseRoom room, @NotNull Team team, @NotNull FullChunk chunk, @NotNull CompoundTag nbt) { 31 | super(chunk, nbt.putCompound("Skin", new CompoundTag())); 32 | this.room = room; 33 | this.team = team; 34 | } 35 | 36 | public void setTowerDefinition(@NotNull TowerDefinition towerDefinition) { 37 | this.towerDefinition = towerDefinition; 38 | this.setMaxHealth(towerDefinition.getMaxHealth()); 39 | this.setHealth(this.getMaxHealth()); 40 | } 41 | 42 | public boolean addTarget(@NotNull EntityCreature entity) { 43 | return this.targetQueue.offer(entity); 44 | } 45 | 46 | public boolean removeTarget(@NotNull EntityCreature entity) { 47 | return this.targetQueue.remove(entity); 48 | } 49 | 50 | @Override 51 | public boolean onUpdate(int currentTick) { 52 | this.checkTarget(); 53 | if (this.nowTarget != null) { 54 | this.seeTarget(this.nowTarget); 55 | if (this.attackTick >= this.towerDefinition.getAttackSpeed()) { 56 | this.fire(); 57 | this.attackTick = 0; 58 | }else { 59 | this.attackTick++; 60 | } 61 | }else { 62 | this.pitch = 0; 63 | } 64 | 65 | //TODO 头顶显示血条 66 | 67 | return super.onUpdate(currentTick); 68 | } 69 | 70 | protected void checkTarget() { 71 | EntityCreature target = this.targetQueue.peek(); 72 | if (target != null) { 73 | double distance = this.distance(target); 74 | if (distance >= this.towerDefinition.getAttackMinRange() && distance <= this.towerDefinition.getAttackMaxRange()) { 75 | //TODO 检查遮挡物 76 | this.nowTarget = target; 77 | return; 78 | } 79 | } 80 | this.nowTarget = null; 81 | } 82 | 83 | protected void seeTarget(Vector3 target) { 84 | double dx = this.x - target.x; 85 | double dy = this.y - (target.y + 0.5); 86 | double dz = this.z - target.z; 87 | double yaw = Math.asin(dx / Math.sqrt(dx * dx + dz * dz)) / Math.PI * 180.0D; 88 | double pitch = Math.round(Math.asin(dy / Math.sqrt(dx * dx + dz * dz + dy * dy)) / Math.PI * 180.0D); 89 | if (dz > 0.0D) { 90 | yaw = -yaw + 180.0D; 91 | } 92 | this.yaw = yaw; 93 | this.headYaw = yaw; 94 | this.pitch = pitch; 95 | } 96 | 97 | protected void fire() { 98 | //TODO 射击 99 | BulletArrow.launch( 100 | this, 101 | this.getDirectionVector(), 102 | 0.05F, 103 | 1.8F, 104 | null); 105 | 106 | //.putDouble("damage", damage) 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/entity/EntityGunWarBomb.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.entity; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.lanink.gunwar.room.base.PlayerGameData; 5 | import cn.lanink.gunwar.room.base.Team; 6 | import cn.lanink.gunwar.room.blasting.BlastingModeRoom; 7 | import cn.nukkit.Player; 8 | import cn.nukkit.entity.data.IntEntityData; 9 | import cn.nukkit.entity.item.EntityPrimedTNT; 10 | import cn.nukkit.level.Sound; 11 | import cn.nukkit.level.format.FullChunk; 12 | import cn.nukkit.level.particle.HugeExplodeSeedParticle; 13 | import cn.nukkit.nbt.tag.CompoundTag; 14 | 15 | import java.util.Map; 16 | 17 | /** 18 | * @author lt_name 19 | */ 20 | public class EntityGunWarBomb extends EntityPrimedTNT { 21 | 22 | private final BlastingModeRoom room; 23 | private final Player source; 24 | 25 | public EntityGunWarBomb(FullChunk chunk, CompoundTag nbt, BlastingModeRoom room, Player source) { 26 | super(chunk, nbt, source); 27 | this.room = room; 28 | this.source = source; 29 | this.setNameTagAlwaysVisible(false); 30 | this.fuse = room.getBombExplosionTime() * 20; 31 | } 32 | 33 | @Override 34 | protected void initEntity() { 35 | super.initEntity(); 36 | this.fuse = 50*20; 37 | } 38 | 39 | @Override 40 | public String getName() { 41 | return GunWar.getInstance().getLanguage().translateString("item_Bomb_Name"); 42 | } 43 | 44 | @Override 45 | public boolean onUpdate(int currentTick) { 46 | if (this.closed) { 47 | return false; 48 | } 49 | int tickDiff = currentTick - this.lastUpdate; 50 | if (tickDiff <= 0 && !justCreated) { 51 | return true; 52 | } 53 | if (this.fuse % 5 == 0) { 54 | this.setDataProperty(new IntEntityData(DATA_FUSE_LENGTH, this.fuse)); 55 | } 56 | this.fuse -= tickDiff; 57 | if (this.fuse <= 0) { 58 | this.level.addSound(this, Sound.RANDOM_EXPLODE); 59 | this.level.addParticle(new HugeExplodeSeedParticle(this)); 60 | for (Map.Entry entry : this.room.getPlayerDataMap().entrySet()) { 61 | double distance = entry.getKey().distance(this); 62 | if ((entry.getValue().getTeam() == Team.RED || entry.getValue().getTeam() == Team.BLUE) && 63 | distance < this.room.getBlastingPointRadius()) { 64 | this.room.lessHealth(entry.getKey(), this, 65 | (float) (20 * (this.room.getBlastingPointRadius() - distance) / this.room.getBlastingPointRadius()) + 5); 66 | } 67 | } 68 | this.kill(); 69 | this.close(); 70 | this.room.bombExplosion(); 71 | return false; 72 | } 73 | this.setNameTag(String.valueOf(this.getExplosionTime())); 74 | this.lastUpdate = currentTick; 75 | this.entityBaseTick(tickDiff); 76 | if (isAlive()) { 77 | motionY -= getGravity(); 78 | move(motionX, motionY, motionZ); 79 | float friction = 1 - getDrag(); 80 | motionX *= friction; 81 | motionY *= friction; 82 | motionZ *= friction; 83 | this.updateMovement(); 84 | if (this.onGround) { 85 | this.motionY *= -0.5; 86 | motionX *= 0.7; 87 | motionZ *= 0.7; 88 | } 89 | } 90 | return true; 91 | } 92 | 93 | @Override 94 | public void explode() { 95 | 96 | } 97 | 98 | @Override 99 | public Player getSource() { 100 | return this.source; 101 | } 102 | 103 | /** 104 | * @return 爆炸倒计时 105 | */ 106 | public int getExplosionTime() { 107 | return this.fuse / 20; 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/item/weapon/ProjectileWeapon.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.item.weapon; 2 | 3 | import cn.lanink.gunwar.item.ItemManage; 4 | import cn.lanink.gunwar.utils.exception.item.weapon.ProjectileWeaponLoadException; 5 | import cn.nukkit.item.ProjectileItem; 6 | import cn.nukkit.level.particle.HugeExplodeSeedParticle; 7 | import cn.nukkit.level.particle.Particle; 8 | import cn.nukkit.math.Vector3; 9 | import cn.nukkit.nbt.tag.CompoundTag; 10 | import cn.nukkit.utils.Config; 11 | 12 | import java.lang.reflect.Constructor; 13 | import java.util.LinkedList; 14 | 15 | /** 16 | * @author lt_name 17 | */ 18 | public class ProjectileWeapon extends BaseWeapon { 19 | 20 | protected float range; 21 | protected String particle; 22 | 23 | public ProjectileWeapon(String name, Config config) throws ProjectileWeaponLoadException { 24 | super(name, config); 25 | if (!(this.item instanceof ProjectileItem)) { 26 | throw new ProjectileWeaponLoadException("name:" + this.getName() + 27 | " ID:" + this.item.getId() + ":" + this.item.getDamage() + 28 | " 不属于抛掷物"); 29 | } 30 | this.particle = config.getString("particle"); 31 | this.range = Math.abs((float) config.getDouble("range")); 32 | 33 | CompoundTag tag = this.getCompoundTag(); 34 | tag.putFloat("range", this.range); 35 | this.setCompoundTag(tag); 36 | } 37 | 38 | @Override 39 | public ItemManage.ItemType getItemType() { 40 | return ItemManage.ItemType.WEAPON_PROJECTILE; 41 | } 42 | 43 | public String getParticle() { 44 | return this.particle; 45 | } 46 | 47 | /** 48 | * @return 有效半径 49 | */ 50 | public float getRange() { 51 | return this.range; 52 | } 53 | 54 | /** 55 | * 根据距离获取伤害 56 | * @param distance 距离 57 | * @return 伤害 58 | */ 59 | public double getDamage(double distance) { 60 | if (distance > this.getRange()) { 61 | return 0; 62 | } 63 | double damage = Math.max((this.getRange() - distance) / this.getRange() * this.getMaxDamage() * 1.1, this.getMinDamage()); 64 | return Math.min(damage, this.getMaxDamage()); 65 | } 66 | 67 | /** 68 | * @param vector3 位置 69 | * @return 粒子 70 | */ 71 | public Particle getParticle(Vector3 vector3) { 72 | try { 73 | String[] stringClass = this.getParticle().split("@"); 74 | String className = "cn.nukkit.level.particle." + stringClass[0]; 75 | Class particleClass = (Class) Class.forName(className); 76 | LinkedList> classList = new LinkedList<>(); 77 | LinkedList valueList = new LinkedList<>(); 78 | String[] strings = stringClass[1].split("&"); 79 | for (String string : strings) { 80 | String[] s = string.split(":"); 81 | if ("Vector3".equalsIgnoreCase(s[0])) { 82 | classList.add(Vector3.class); 83 | valueList.add(vector3); 84 | }else if ("int".equalsIgnoreCase(s[0])) { 85 | classList.add(int.class); 86 | valueList.add(Integer.parseInt(s[1])); 87 | }else if ("float".equalsIgnoreCase(s[0])) { 88 | classList.add(float.class); 89 | valueList.add(Float.parseFloat(s[1])); 90 | } 91 | } 92 | Constructor constructor = particleClass.getConstructor(classList.toArray(new Class[]{})); 93 | return constructor.newInstance(valueList.toArray()); 94 | } catch (Exception e) { 95 | e.printStackTrace(); 96 | } 97 | return new HugeExplodeSeedParticle(vector3); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/item/weapon/BaseWeapon.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.item.weapon; 2 | 3 | import cn.lanink.gunwar.item.base.BaseItem; 4 | import cn.lanink.gunwar.utils.Tools; 5 | import cn.nukkit.item.enchantment.Enchantment; 6 | import cn.nukkit.nbt.tag.CompoundTag; 7 | import cn.nukkit.potion.Effect; 8 | import cn.nukkit.utils.Config; 9 | 10 | import java.util.ArrayList; 11 | import java.util.LinkedList; 12 | import java.util.Map; 13 | 14 | /** 15 | * @author lt_name 16 | */ 17 | public abstract class BaseWeapon extends BaseItem { 18 | 19 | protected final double minDamage; 20 | protected final double maxDamage; 21 | public final ArrayList effects = new ArrayList<>(); 22 | protected final int attackCooldown; 23 | protected final String killMessage; 24 | 25 | public BaseWeapon(String name, Config config) { 26 | super(name, config); 27 | String[] stringDamage = config.getString("damage").split("-"); 28 | this.minDamage = Math.abs(Double.parseDouble(stringDamage[0])); 29 | if (stringDamage.length > 1) { 30 | this.maxDamage = Math.abs(Double.parseDouble(stringDamage[1])); 31 | }else { 32 | this.maxDamage = minDamage; 33 | } 34 | for (Map map : config.getMapList("effect")) { 35 | try { 36 | int id = (int) map.getOrDefault("id", 9); 37 | int amplifier = (int) map.getOrDefault("amplifier", 1); 38 | int duration = (int) map.getOrDefault("duration", 20); 39 | boolean visible = (boolean) map.getOrDefault("visible", true); 40 | Effect effect = Effect.getEffect(id).setAmplifier(amplifier).setDuration(duration).setVisible(visible); 41 | Map color = (Map) map.get("color"); 42 | if (visible && color != null) { 43 | effect.setColor(color.get("r"), color.get("g"), color.get("b")); 44 | } 45 | this.effects.add(effect); 46 | } catch (Exception e) { 47 | e.printStackTrace(); 48 | } 49 | } 50 | this.attackCooldown = config.getInt("attackCooldown"); 51 | for (Map map : config.getMapList("enchantment")) { 52 | try { 53 | int id = (int) map.getOrDefault("id", 17); 54 | int level = (int) map.getOrDefault("level", 1); 55 | Enchantment enchantment = Enchantment.get(id); 56 | enchantment.setLevel(level); 57 | this.item.addEnchantment(enchantment); 58 | } catch (Exception e) { 59 | e.printStackTrace(); 60 | } 61 | } 62 | this.killMessage = config.getString("killMessage"); 63 | 64 | CompoundTag tag = this.getCompoundTag(); 65 | tag.putDouble("minDamage", this.minDamage) 66 | .putDouble("maxDamage", this.maxDamage) 67 | .putInt("attackCooldown", this.attackCooldown) 68 | .putString("killMessage", this.killMessage); 69 | this.setCompoundTag(tag); 70 | } 71 | 72 | public double getMinDamage() { 73 | return this.minDamage; 74 | } 75 | 76 | public double getMaxDamage() { 77 | return this.maxDamage; 78 | } 79 | 80 | public double getRandomDamage() { 81 | return Tools.randomDouble(this.getMinDamage(), this.getMaxDamage()); 82 | } 83 | 84 | public LinkedList getEffects() { 85 | LinkedList list = new LinkedList<>(); 86 | for (Effect effect : this.effects) { 87 | list.add(effect.clone()); 88 | } 89 | return list; 90 | } 91 | 92 | /** 93 | * @return 攻击间隔 94 | */ 95 | public int getAttackCooldown() { 96 | return this.attackCooldown; 97 | } 98 | 99 | public String getKillMessage() { 100 | return this.killMessage; 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/entity/bullet/BulletArrow.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.entity.bullet; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.nukkit.Player; 5 | import cn.nukkit.Server; 6 | import cn.nukkit.entity.Entity; 7 | import cn.nukkit.entity.EntityCreature; 8 | import cn.nukkit.entity.projectile.EntityArrow; 9 | import cn.nukkit.level.ParticleEffect; 10 | import cn.nukkit.level.format.FullChunk; 11 | import cn.nukkit.math.Vector3; 12 | import cn.nukkit.nbt.tag.CompoundTag; 13 | import cn.nukkit.nbt.tag.DoubleTag; 14 | import cn.nukkit.nbt.tag.FloatTag; 15 | import cn.nukkit.nbt.tag.ListTag; 16 | import cn.nukkit.network.protocol.LevelSoundEventPacket; 17 | 18 | /** 19 | * @author LT_Name 20 | */ 21 | public class BulletArrow extends EntityArrow implements IBullet { 22 | 23 | protected float gravity = 0.05F; 24 | protected ParticleEffect particleEffect; 25 | 26 | private BulletArrow(FullChunk chunk, CompoundTag nbt, Entity shootingEntity) { 27 | super(chunk, nbt, shootingEntity); 28 | } 29 | 30 | public static void launch(EntityCreature entityCreature, 31 | Vector3 directionVector, 32 | float gravity, 33 | float motionMultiply, 34 | ParticleEffect particleEffect 35 | /*CompoundTag compoundTag*/) { 36 | CompoundTag nbt = (new CompoundTag()) 37 | .putList((new ListTag<>("Pos")) 38 | .add(new DoubleTag("", entityCreature.x)) 39 | .add(new DoubleTag("", entityCreature.y + entityCreature.getEyeHeight())) 40 | .add(new DoubleTag("", entityCreature.z))) 41 | .putList((new ListTag<>("Motion")) 42 | .add(new DoubleTag("", directionVector.x)) 43 | .add(new DoubleTag("", directionVector.y)) 44 | .add(new DoubleTag("", directionVector.z))) 45 | .putList((new ListTag<>("Rotation")) 46 | .add(new FloatTag("", (float)entityCreature.yaw)) 47 | .add(new FloatTag("", (float)entityCreature.pitch))); 48 | //nbt.putCompound(BaseItem.GUN_WAR_ITEM_TAG, compoundTag); 49 | BulletArrow bulletArrow = new BulletArrow(entityCreature.getChunk(), nbt, entityCreature); 50 | bulletArrow.setGravity(gravity); 51 | bulletArrow.setParticleEffect(particleEffect); 52 | bulletArrow.setMotion(bulletArrow.getMotion().multiply(motionMultiply)); 53 | bulletArrow.setPickupMode(PICKUP_NONE); 54 | for (Player p : entityCreature.getLevel().getChunkPlayers(entityCreature.getFloorX() >> 4, entityCreature.getFloorZ() >> 4).values()) { 55 | if (p != entityCreature) { 56 | bulletArrow.spawnTo(p); 57 | } 58 | } 59 | if (entityCreature instanceof Player) { 60 | Server.getInstance().getScheduler().scheduleDelayedTask(GunWar.getInstance(), () -> { 61 | if (!bulletArrow.isClosed()) { 62 | bulletArrow.spawnTo((Player) entityCreature); 63 | } 64 | }, 10); 65 | } 66 | entityCreature.getLevel().addLevelSoundEvent(entityCreature, LevelSoundEventPacket.SOUND_BOW); 67 | } 68 | 69 | @Override 70 | public void setGravity(float gravity) { 71 | this.gravity = gravity; 72 | } 73 | 74 | @Override 75 | public float getGravity() { 76 | return this.gravity; 77 | } 78 | 79 | @Override 80 | public void setParticleEffect(ParticleEffect particleEffect) { 81 | this.particleEffect = particleEffect; 82 | } 83 | 84 | @Override 85 | public boolean onUpdate(int currentTick) { 86 | boolean onUpdate = super.onUpdate(currentTick); 87 | if (this.particleEffect != null && !this.closed && 88 | !this.onGround && !this.hadCollision && currentTick %5 == 0) { 89 | this.level.addParticleEffect(this, this.particleEffect); 90 | } 91 | return onUpdate; 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/listener/defaults/DefaultChatListener.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.listener.defaults; 2 | 3 | import cn.lanink.gamecore.listener.BaseGameListener; 4 | import cn.lanink.gamecore.room.IRoomStatus; 5 | import cn.lanink.gunwar.GunWar; 6 | import cn.lanink.gunwar.room.base.BaseRoom; 7 | import cn.lanink.gunwar.room.base.Team; 8 | import cn.lanink.gunwar.utils.Tools; 9 | import cn.nukkit.Player; 10 | import cn.nukkit.event.EventHandler; 11 | import cn.nukkit.event.EventPriority; 12 | import cn.nukkit.event.player.PlayerChatEvent; 13 | import cn.nukkit.event.player.PlayerCommandPreprocessEvent; 14 | 15 | /** 16 | * @author lt_name 17 | */ 18 | @SuppressWarnings("unused") 19 | public class DefaultChatListener extends BaseGameListener { 20 | 21 | private final GunWar gunWar = GunWar.getInstance(); 22 | 23 | /** 24 | * 玩家执行命令事件 25 | * @param event 事件 26 | */ 27 | @EventHandler 28 | public void onCommandPreprocess(PlayerCommandPreprocessEvent event) { 29 | Player player = event.getPlayer(); 30 | String message = event.getMessage(); 31 | if (player == null || message == null) { 32 | return; 33 | } 34 | String[] split = message.replace("/", "").split(" "); 35 | if (split.length == 0) { 36 | return; 37 | } 38 | message = split[0]; 39 | BaseRoom room = this.getListenerRoom(player.getLevel()); 40 | if (room == null || !room.isPlaying(player)) { 41 | return; 42 | } 43 | if (this.gunWar.getCmdUser().equalsIgnoreCase(message) || 44 | this.gunWar.getCmdAdmin().equalsIgnoreCase(message)) { 45 | return; 46 | } 47 | for (String string : this.gunWar.getCmdWhitelist()) { 48 | if (string.equalsIgnoreCase(message)) { 49 | return; 50 | } 51 | } 52 | event.setMessage(""); 53 | event.setCancelled(true); 54 | player.sendMessage(this.gunWar.getLanguage().translateString("useCmdInRoom")); 55 | } 56 | 57 | /** 58 | * 玩家聊天事件 59 | * @param event 事件 60 | */ 61 | @EventHandler(priority = EventPriority.LOWEST) 62 | public void onChat(PlayerChatEvent event) { 63 | Player player = event.getPlayer(); 64 | String message = event.getMessage(); 65 | if (player == null || message == null) { 66 | return; 67 | } 68 | BaseRoom room = this.getListenerRoom(player.getLevel()); 69 | if (room == null || !room.isPlaying(player)) { 70 | for (BaseRoom r : this.gunWar.getGameRoomManager().getGameRoomMap().values()) { 71 | for (Player p : r.getPlayerDataMap().keySet()) { 72 | event.getRecipients().remove(p); 73 | } 74 | } 75 | return; 76 | } 77 | if (message.startsWith("@") || room.getStatus() != IRoomStatus.ROOM_STATUS_GAME) { 78 | message = this.gunWar.getLanguage().translateString("playerAllChat", player.getName(), message); 79 | Tools.sendMessage(room, message); 80 | }else { 81 | message = this.gunWar.getLanguage().translateString("playerTeamChat", player.getName(), message); 82 | Team team = room.getPlayerTeamAccurate(player); 83 | for (Player target : room.getPlayerDataMap().keySet()) { 84 | Team targetTeam = room.getPlayerTeamAccurate(target); 85 | if (team == targetTeam) { 86 | target.sendMessage(message); 87 | } else if (team == Team.RED || team == Team.RED_DEATH) { 88 | if (targetTeam == Team.RED || targetTeam == Team.RED_DEATH) { 89 | target.sendMessage(message); 90 | } 91 | } else if (team == Team.BLUE || team == Team.BLUE_DEATH) { 92 | if (targetTeam == Team.BLUE || targetTeam == Team.BLUE_DEATH) { 93 | target.sendMessage(message); 94 | } 95 | } 96 | } 97 | } 98 | event.setMessage(""); 99 | event.setCancelled(true); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/tasks/game/blasting/PlantBombTask.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.tasks.game.blasting; 2 | 3 | import cn.lanink.gamecore.GameCore; 4 | import cn.lanink.gunwar.GunWar; 5 | import cn.lanink.gunwar.entity.EntityGunWarBomb; 6 | import cn.lanink.gunwar.entity.EntityGunWarBombBlock; 7 | import cn.lanink.gunwar.item.ItemManage; 8 | import cn.lanink.gunwar.room.base.IntegralConfig; 9 | import cn.lanink.gunwar.room.blasting.BlastingModeRoom; 10 | import cn.lanink.gunwar.utils.Tools; 11 | import cn.nukkit.Player; 12 | import cn.nukkit.Server; 13 | import cn.nukkit.entity.Entity; 14 | import cn.nukkit.item.Item; 15 | import cn.nukkit.math.Vector3; 16 | import cn.nukkit.nbt.tag.CompoundTag; 17 | import cn.nukkit.scheduler.PluginTask; 18 | 19 | import java.util.HashSet; 20 | 21 | public class PlantBombTask extends PluginTask { 22 | 23 | public static final HashSet PLANT_BOMB_PLAYERS = new HashSet<>(); 24 | private final BlastingModeRoom room; 25 | private final Player player; 26 | private final Vector3 playerPosition; 27 | private final Vector3 placePoint; 28 | private final double base; 29 | private double placementProgress; 30 | public static final int MAX_PLACEMENT_PROGRESS = 50; 31 | 32 | public PlantBombTask(BlastingModeRoom room, Player player, Vector3 placePoint, double base) { 33 | super(GunWar.getInstance()); 34 | this.room = room; 35 | this.player = player; 36 | this.playerPosition = player.clone(); 37 | this.placePoint = placePoint; 38 | this.placePoint.y += 1; 39 | this.placePoint.x += 0.5; 40 | this.placePoint.z += 0.5; 41 | this.base = base; 42 | PLANT_BOMB_PLAYERS.add(player); 43 | } 44 | 45 | @Override 46 | public void onRun(int i) { 47 | this.placementProgress += this.base; 48 | if (i%5 == 0) { 49 | this.player.sendTip(Tools.getShowStringProgress((int) this.placementProgress, MAX_PLACEMENT_PROGRESS)); 50 | } 51 | Item item = player.getInventory().getItemInHand(); 52 | if (!item.hasCompoundTag() || 53 | item.getNamedTag().getInt(ItemManage.GUN_WAR_ITEM_TYPE_TAG) != 201 || 54 | this.playerPosition.distance(this.player) > 0.5 || 55 | this.placementProgress >= MAX_PLACEMENT_PROGRESS || 56 | !PLANT_BOMB_PLAYERS.contains(this.player)) { 57 | this.cancel(); 58 | } 59 | } 60 | 61 | @Override 62 | public void onCancel() { 63 | Server.getInstance().getScheduler().scheduleTask(this.owner, () -> { 64 | if (this.placementProgress >= MAX_PLACEMENT_PROGRESS) { 65 | Tools.sendTitle(this.room, "", this.owner.getLanguage().translateString("game_blasting_plantBomb")); 66 | //移除炸弹物品 67 | Tools.removeGunWarItem(this.player.getInventory(), Tools.getItem(201)); 68 | 69 | CompoundTag nbt = Entity.getDefaultNBT(this.placePoint); 70 | EntityGunWarBomb entityBomb = new EntityGunWarBomb( 71 | this.player.getChunk(), nbt,this.room, this.player); 72 | entityBomb.setPosition(this.placePoint); 73 | entityBomb.spawnToAll(); 74 | this.room.setEntityGunWarBomb(entityBomb); 75 | 76 | EntityGunWarBombBlock entityBombBlock = new EntityGunWarBombBlock(this.player.getChunk(), nbt); 77 | entityBombBlock.setPosition(this.placePoint); 78 | entityBombBlock.setSkin(GameCore.DEFAULT_SKIN); 79 | Server.getInstance().getScheduler().scheduleDelayedTask(this.getOwner(), () -> { 80 | if (!entityBombBlock.isClosed()) { 81 | entityBombBlock.spawnToAll(); 82 | } 83 | }, 10); 84 | this.room.setEntityGunWarBombBlock(entityBombBlock); 85 | 86 | this.room.addPlayerIntegral(this.player, IntegralConfig.getIntegral(IntegralConfig.IntegralType.BOMB_SCORE)); 87 | }else { 88 | this.player.sendTitle("", this.owner.getLanguage().translateString("game_blasting_cancelPlantBomb")); 89 | } 90 | this.player.sendTip(" "); 91 | PLANT_BOMB_PLAYERS.remove(this.player); 92 | }); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/listener/defaults/PlayerJoinAndQuit.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.listener.defaults; 2 | 3 | import cn.lanink.gamecore.utils.PlayerDataUtils; 4 | import cn.lanink.gamecore.utils.Tips; 5 | import cn.lanink.gunwar.GunWar; 6 | import cn.lanink.gunwar.gui.GuiCreate; 7 | import cn.lanink.gunwar.item.ItemManage; 8 | import cn.lanink.gunwar.item.weapon.GunWeapon; 9 | import cn.lanink.gunwar.room.base.BaseRoom; 10 | import cn.lanink.gunwar.tasks.game.blasting.DemolitionBombTask; 11 | import cn.lanink.gunwar.tasks.game.blasting.PlantBombTask; 12 | import cn.lanink.gunwar.utils.Tools; 13 | import cn.nukkit.Player; 14 | import cn.nukkit.Server; 15 | import cn.nukkit.event.EventHandler; 16 | import cn.nukkit.event.Listener; 17 | import cn.nukkit.event.player.PlayerJoinEvent; 18 | import cn.nukkit.event.player.PlayerQuitEvent; 19 | import cn.nukkit.event.player.PlayerTeleportEvent; 20 | import cn.nukkit.scheduler.Task; 21 | 22 | import java.io.File; 23 | import java.util.Map; 24 | 25 | /** 26 | * 玩家进入/退出服务器 或传送到其他世界时,退出房间 27 | */ 28 | public class PlayerJoinAndQuit implements Listener { 29 | 30 | private final GunWar gunWar; 31 | 32 | public PlayerJoinAndQuit(GunWar gunWar) { 33 | this.gunWar = gunWar; 34 | } 35 | 36 | @EventHandler 37 | public void onPlayerJoin(PlayerJoinEvent event) { 38 | Player player = event.getPlayer(); 39 | if (player != null && this.gunWar.getGameRoomManager().hasGameRoom(player.getLevel().getFolderName())) { 40 | Server.getInstance().getScheduler().scheduleDelayedTask(this.gunWar, new Task() { 41 | @Override 42 | public void onRun(int i) { 43 | if (player.isOnline()) { 44 | Tools.rePlayerState(player ,false); 45 | if (gunWar.isHasTips()) { 46 | Tips.removeTipsConfig(player.getLevel().getName(), player); 47 | } 48 | 49 | File file = new File(GunWar.getInstance().getDataFolder() + "/PlayerInventory/" + player.getName() + ".json"); 50 | if (file.exists()) { 51 | PlayerDataUtils.PlayerData playerData = PlayerDataUtils.create(player, file); 52 | if (file.delete()) { 53 | playerData.restoreAll(); 54 | } 55 | } 56 | 57 | player.teleport(Server.getInstance().getDefaultLevel().getSafeSpawn()); 58 | } 59 | } 60 | }, 10); 61 | } 62 | } 63 | 64 | @EventHandler 65 | public void onPlayerQuit(PlayerQuitEvent event) { 66 | Player player = event.getPlayer(); 67 | if (player == null) { 68 | return; 69 | } 70 | if (this.gunWar.setRoomTask.containsKey(player)) { 71 | this.gunWar.setRoomTask.get(player).cancel(); 72 | } 73 | for (BaseRoom room : this.gunWar.getGameRoomManager().getGameRoomMap().values()) { 74 | if (room.isPlaying(player)) { 75 | room.quitRoom(player); 76 | } 77 | } 78 | ItemManage.getPlayerAttackTime().remove(player); 79 | for (GunWeapon weapon : ItemManage.getGunWeaponMap().values()) { 80 | weapon.getMagazineMap().remove(player); 81 | } 82 | PlantBombTask.PLANT_BOMB_PLAYERS.remove(player); 83 | DemolitionBombTask.DEMOLITION_BOMB_PLAYERS.remove(player); 84 | GuiCreate.UI_CACHE.remove(player); 85 | } 86 | 87 | @EventHandler 88 | public void onPlayerTp(PlayerTeleportEvent event) { 89 | Player player = event.getPlayer(); 90 | String fromLevel = event.getFrom().getLevel() == null ? null : event.getFrom().getLevel().getName(); 91 | String toLevel = event.getTo().getLevel()== null ? null : event.getTo().getLevel().getName(); 92 | if (player == null || fromLevel == null || toLevel == null) { 93 | return; 94 | } 95 | if (!fromLevel.equals(toLevel)) { 96 | Map room = this.gunWar.getGameRoomManager().getGameRoomMap(); 97 | if (room.containsKey(fromLevel) && room.get(fromLevel).isPlaying(player)) { 98 | room.get(fromLevel).quitRoom(player); 99 | }else if (!player.isOp() && room.containsKey(toLevel) && 100 | !room.get(toLevel).isPlaying(player)) { 101 | event.setCancelled(true); 102 | player.sendMessage(this.gunWar.getLanguage().translateString("tpJoinRoomLevel")); 103 | } 104 | } 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/tasks/game/ctf/FlagTask.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.tasks.game.ctf; 2 | 3 | import cn.lanink.gamecore.room.IRoomStatus; 4 | import cn.lanink.gunwar.GunWar; 5 | import cn.lanink.gunwar.entity.flag.EntityFlag; 6 | import cn.lanink.gunwar.entity.flag.EntityFlagStand; 7 | import cn.lanink.gunwar.room.capturetheflag.CTFModeRoom; 8 | import cn.lanink.gunwar.utils.FlagSkinType; 9 | import cn.nukkit.entity.data.Skin; 10 | import cn.nukkit.math.Vector3; 11 | import cn.nukkit.nbt.tag.CompoundTag; 12 | import cn.nukkit.scheduler.PluginTask; 13 | 14 | /** 15 | * 夺旗模式 旗帜生成检查 位置检查 16 | * 17 | * @author lt_name 18 | */ 19 | public class FlagTask extends PluginTask { 20 | 21 | private final CTFModeRoom room; 22 | 23 | public FlagTask(GunWar owner, CTFModeRoom room) { 24 | super(owner); 25 | this.room = room; 26 | } 27 | 28 | @Override 29 | public void onRun(int i) { 30 | if (this.room.getStatus() != IRoomStatus.ROOM_STATUS_GAME) { 31 | this.cancel(); 32 | return; 33 | } 34 | //旗帜与底座生成 35 | //红方底座 36 | if (room.redFlagStand == null || room.redFlagStand.isClosed()) { 37 | Skin skin = owner.getFlagSkin(FlagSkinType.FLAG_STAND_RED); 38 | CompoundTag nbt = EntityFlagStand.getDefaultNBT(room.getRedSpawn()); 39 | nbt.putFloat("Scale", 1.0F); 40 | nbt.putCompound("Skin", new CompoundTag() 41 | .putByteArray("Data", skin.getSkinData().data) 42 | .putString("ModelId", skin.getSkinId())); 43 | nbt.putInt("GunWarTeam", 1); 44 | EntityFlagStand entityFlagStand = new EntityFlagStand(room.getRedSpawn().getChunk(), nbt); 45 | entityFlagStand.setSkin(skin); 46 | entityFlagStand.spawnToAll(); 47 | room.redFlagStand = entityFlagStand; 48 | } 49 | //红方旗帜 50 | if (room.redFlag == null || room.redFlag.isClosed()) { 51 | Skin skin = owner.getFlagSkin(FlagSkinType.FLAG_RED); 52 | CompoundTag nbt = EntityFlag.getDefaultNBT(new Vector3(room.getRedSpawn().getX(), 53 | room.getRedSpawn().getY() + 0.3D, 54 | room.getRedSpawn().getZ())); 55 | nbt.putCompound("Skin", new CompoundTag() 56 | .putByteArray("Data", skin.getSkinData().data) 57 | .putString("ModelId", skin.getSkinId())); 58 | nbt.putFloat("Scale", 1.0F); 59 | nbt.putInt("GunWarTeam", 11); 60 | EntityFlag entityFlag = new EntityFlag(room.getRedSpawn().getChunk(), nbt); 61 | entityFlag.setSkin(skin); 62 | entityFlag.spawnToAll(); 63 | room.redFlag = entityFlag; 64 | } 65 | //蓝方底座 66 | if (room.blueFlagStand == null || room.blueFlagStand.isClosed()) { 67 | Skin skin = owner.getFlagSkin(FlagSkinType.FLAG_STAND_BLUE); 68 | CompoundTag nbt = EntityFlagStand.getDefaultNBT(room.getBlueSpawn()); 69 | nbt.putFloat("Scale", 1.0F); 70 | nbt.putCompound("Skin", new CompoundTag() 71 | .putByteArray("Data", skin.getSkinData().data) 72 | .putString("ModelId", skin.getSkinId())); 73 | nbt.putInt("GunWarTeam", 2); 74 | EntityFlagStand entityFlagStand = new EntityFlagStand(room.getRedSpawn().getChunk(), nbt); 75 | entityFlagStand.setSkin(skin); 76 | entityFlagStand.spawnToAll(); 77 | room.blueFlagStand = entityFlagStand; 78 | } 79 | //蓝方旗帜 80 | if (room.blueFlag == null || room.blueFlag.isClosed()) { 81 | Skin skin = owner.getFlagSkin(FlagSkinType.FLAG_BLUE); 82 | CompoundTag nbt = EntityFlag.getDefaultNBT(new Vector3(room.getBlueSpawn().getX(), 83 | room.getBlueSpawn().getY() + 0.3D, 84 | room.getBlueSpawn().getZ())); 85 | nbt.putCompound("Skin", new CompoundTag() 86 | .putByteArray("Data", skin.getSkinData().data) 87 | .putString("ModelId", skin.getSkinId())); 88 | nbt.putFloat("Scale", 1.0F); 89 | nbt.putInt("GunWarTeam", 12); 90 | EntityFlag entityFlag = new EntityFlag(room.getRedSpawn().getChunk(), nbt); 91 | entityFlag.setSkin(skin); 92 | entityFlag.spawnToAll(); 93 | room.blueFlag = entityFlag; 94 | } 95 | 96 | //旗帜移动 97 | if (this.room.haveRedFlag != null) { 98 | this.room.redFlag.setPosition(this.room.haveRedFlag.add(0, this.room.haveRedFlag.getEyeHeight() + 0.5, 0)); 99 | } 100 | if (this.room.haveBlueFlag != null) { 101 | this.room.blueFlag.setPosition(this.room.haveBlueFlag.add(0, this.room.haveBlueFlag.getEyeHeight() + 0.5, 0)); 102 | } 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/room/freeforall/FreeForAllModeRoom.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.room.freeforall; 2 | 3 | import cn.lanink.gamecore.utils.exception.RoomLoadException; 4 | import cn.lanink.gunwar.GunWar; 5 | import cn.lanink.gunwar.room.base.BaseRespawnModeRoom; 6 | import cn.lanink.gunwar.room.base.PlayerGameData; 7 | import cn.lanink.gunwar.room.base.Team; 8 | import cn.lanink.gunwar.tasks.VictoryTask; 9 | import cn.lanink.gunwar.utils.Tools; 10 | import cn.nukkit.Player; 11 | import cn.nukkit.Server; 12 | import cn.nukkit.level.Level; 13 | import cn.nukkit.level.Position; 14 | import cn.nukkit.math.Vector3; 15 | import cn.nukkit.utils.Config; 16 | import org.jetbrains.annotations.NotNull; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Map; 20 | 21 | /** 22 | * F.F.A 个人战 模式房间 23 | * 24 | * @author LT_Name 25 | */ 26 | public class FreeForAllModeRoom extends BaseRespawnModeRoom { 27 | 28 | private final ArrayList randomSpawns = new ArrayList<>(); 29 | 30 | /** 31 | * 初始化 32 | * 33 | * @param level 游戏世界 34 | * @param config 配置文件 35 | */ 36 | public FreeForAllModeRoom(@NotNull Level level, @NotNull Config config) throws RoomLoadException { 37 | super(level, config); 38 | 39 | //针对未配置的情况,缩短默认的时间 40 | this.respawnNeedTime = config.getInt("respawn-need-time", 3); 41 | 42 | for (String string : config.getStringList("randomSpawns")) { 43 | this.randomSpawns.add(Tools.stringToVector3(string)); 44 | } 45 | if (this.randomSpawns.isEmpty()) { 46 | throw new RoomLoadException("randomSpawns is empty"); 47 | } 48 | } 49 | 50 | @Override 51 | public void saveConfig() { 52 | super.saveConfig(); 53 | 54 | //移除FFA模式不需要的配置 55 | this.config.remove("redTeamInitialItems"); 56 | this.config.remove("blueTeamInitialItems"); 57 | this.config.remove("roundEndCleanItem"); 58 | 59 | ArrayList randomSpawnList = new ArrayList<>(); 60 | for (Vector3 vector3 : this.randomSpawns) { 61 | randomSpawnList.add(Tools.vector3ToString(vector3)); 62 | } 63 | this.config.set("randomSpawns", randomSpawnList); 64 | 65 | this.config.save(); 66 | } 67 | 68 | @Override 69 | public boolean canDamageTeammates() { 70 | return true; 71 | } 72 | 73 | @Override 74 | protected void checkTeamPlayerCount() { 75 | if (this.getPlayerDataMap().size() < 2) { 76 | this.roundEnd(Team.NULL); 77 | } 78 | int killAtMost = this.getKillAtMost(); 79 | this.redScore = killAtMost; 80 | this.blueScore = this.getVictoryScore(); 81 | if (killAtMost >= this.getVictoryScore()) { 82 | this.roundEnd(Team.NULL); 83 | } 84 | } 85 | 86 | public int getKillAtMost() { 87 | ArrayList list = new ArrayList<>(this.getPlayerDataMap().values()); 88 | list.sort((o1, o2) -> o2.getKillCount() - o1.getKillCount()); 89 | if (!list.isEmpty()) { 90 | return list.get(0).getKillCount(); 91 | } 92 | return 0; 93 | } 94 | 95 | @Override 96 | public void assignTeam() { 97 | for (Map.Entry entry : this.getPlayerDataMap().entrySet()) { 98 | entry.getValue().setTeam(Team.RED); 99 | } 100 | } 101 | 102 | @Override 103 | public void roundEnd(Team victory) { 104 | ArrayList list = new ArrayList<>(this.getPlayerDataMap().values()); 105 | list.sort((o1, o2) -> o2.getKillCount() - o1.getKillCount()); 106 | this.setStatus(ROOM_STATUS_VICTORY); 107 | if (!list.isEmpty()) { 108 | Server.getInstance().getScheduler().scheduleRepeatingTask( 109 | this.gunWar, 110 | new VictoryTask(this.gunWar, this, list.get(0).getPlayer()), 111 | 20 112 | ); 113 | } else { 114 | this.endGame(); 115 | } 116 | } 117 | 118 | @Override 119 | public void playerRespawn(Player player) { 120 | super.playerRespawn(player); 121 | 122 | player.getInventory().clearAll(); 123 | player.getUIInventory().clearAll(); 124 | 125 | Tools.giveItem(this, player, Team.NULL, !this.isRoundEndCleanItem()); 126 | 127 | //player.teleport(this.randomSpawns.get(GunWar.RANDOM.nextInt(this.randomSpawns.size()))); 128 | } 129 | 130 | @Override 131 | public Position getRedSpawn() { 132 | return Position.fromObject(this.randomSpawns.get(GunWar.RANDOM.nextInt(this.randomSpawns.size())), this.getLevel()); 133 | } 134 | 135 | @Override 136 | public Position getBlueSpawn() { 137 | return Position.fromObject(this.randomSpawns.get(GunWar.RANDOM.nextInt(this.randomSpawns.size())), this.getLevel()); 138 | } 139 | 140 | @Override 141 | public ArrayList getRedTeamInitialItems() { 142 | return new ArrayList<>(); 143 | } 144 | 145 | @Override 146 | public ArrayList getBlueTeamInitialItems() { 147 | return new ArrayList<>(); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/tasks/WaitTask.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.tasks; 2 | 3 | import cn.lanink.gamecore.room.IRoomStatus; 4 | import cn.lanink.gamecore.utils.Language; 5 | import cn.lanink.gunwar.GunWar; 6 | import cn.lanink.gunwar.room.base.BaseRoom; 7 | import cn.lanink.gunwar.room.base.PlayerGameData; 8 | import cn.lanink.gunwar.room.base.RoomConfig; 9 | import cn.lanink.gunwar.utils.Tools; 10 | import cn.nukkit.Player; 11 | import cn.nukkit.Server; 12 | import cn.nukkit.level.Sound; 13 | import cn.nukkit.scheduler.PluginTask; 14 | 15 | import java.util.LinkedList; 16 | import java.util.Map; 17 | 18 | 19 | public class WaitTask extends PluginTask { 20 | 21 | private final Language language; 22 | private final BaseRoom room; 23 | 24 | public WaitTask(GunWar owner, BaseRoom room) { 25 | super(owner); 26 | this.language = owner.getLanguage(); 27 | this.room = room; 28 | } 29 | 30 | @Override 31 | public void onRun(int i) { 32 | if (this.room.getStatus() != IRoomStatus.ROOM_STATUS_WAIT) { 33 | this.cancel(); 34 | return; 35 | } 36 | 37 | for (Player player : this.room.getPlayerDataMap().keySet()) { 38 | if (this.room.getSupplyType() != RoomConfig.SupplyType.CLOSE) { 39 | player.getInventory().setItem(0, Tools.getItem(13)); //商店 40 | } 41 | player.getInventory().setItem(3, Tools.getItem(11)); //队伍选择 42 | player.getInventory().setItem(5, Tools.getItem(12)); //队伍选择 43 | player.getInventory().setItem(8, Tools.getItem(10)); //退出房间 44 | } 45 | 46 | if (this.room.getPlayerDataMap().size() >= this.room.getMinPlayers()) { 47 | if (this.room.getPlayerDataMap().size() == this.room.getMaxPlayers() && this.room.waitTime > 10) { 48 | this.room.waitTime = 10; 49 | } 50 | this.room.waitTime--; 51 | if (this.room.waitTime > 0) { 52 | String title = "§e"; 53 | if (this.room.waitTime <= 10) { 54 | if (this.room.waitTime <= 3) { 55 | title = "§c"; 56 | Tools.playSound(this.room, Sound.NOTE_HARP); 57 | } else { 58 | Tools.playSound(this.room, Sound.NOTE_BASSATTACK); 59 | } 60 | title += this.room.waitTime; 61 | for (Player player : this.room.getPlayerDataMap().keySet()) { 62 | player.sendTitle(title, "", 0, 15, 5); 63 | } 64 | } 65 | for (Map.Entry entry : room.getPlayerDataMap().entrySet()) { 66 | LinkedList ms = new LinkedList<>(); 67 | for (String string : this.language.translateString("waitTimeScoreBoard").split("\n")) { 68 | ms.add(string.replace("%gameMode%", Tools.getShowGameMode(this.room.getGameMode())) 69 | .replace("%team%", entry.getValue().getTeam().getShowName()) 70 | .replace("%playerNumber%", room.getPlayerDataMap().size() + "") 71 | .replace("%minPlayerNumber%", room.getMinPlayers() + "") 72 | .replace("%maxPlayerNumber%", room.getMaxPlayers() + "") 73 | .replace("%time%", room.waitTime + "")); 74 | } 75 | owner.getScoreboard().showScoreboard(entry.getKey(), this.language.translateString("scoreBoardTitle"), ms); 76 | } 77 | }else { 78 | this.room.startGame(); 79 | Server.getInstance().getScheduler().scheduleDelayedTask(this.owner, 80 | () -> Tools.playSound(this.room, Sound.NOTE_FLUTE), 2, true); 81 | this.cancel(); 82 | } 83 | }else if (!this.room.getPlayerDataMap().isEmpty()) { 84 | if (this.room.waitTime != this.room.getSetWaitTime()) { 85 | this.room.waitTime = this.room.getSetWaitTime(); 86 | } 87 | for (Map.Entry entry : room.getPlayerDataMap().entrySet()) { 88 | LinkedList ms = new LinkedList<>(); 89 | for (String string : language.translateString("waitScoreBoard").split("\n")) { 90 | ms.add(string.replace("%gameMode%", Tools.getShowGameMode(this.room.getGameMode())) 91 | .replace("%team%", entry.getValue().getTeam().getShowName()) 92 | .replace("%playerNumber%", room.getPlayerDataMap().size() + "") 93 | .replace("%minPlayerNumber%", room.getMinPlayers() + "") 94 | .replace("%maxPlayerNumber%", room.getMaxPlayers() + "")); 95 | } 96 | owner.getScoreboard().showScoreboard(entry.getKey(), this.language.translateString("scoreBoardTitle"), ms); 97 | } 98 | }else { 99 | this.room.endGame(); 100 | this.cancel(); 101 | } 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/supplier/SupplyConfig.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.supplier; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.lanink.gunwar.supplier.items.SupplyItemConfig; 5 | import cn.lanink.gunwar.supplier.pages.SupplyPageConfig; 6 | import cn.lanink.gunwar.utils.exception.supply.SupplyConfigLoadException; 7 | import cn.nukkit.utils.Config; 8 | import com.google.common.collect.ImmutableMap; 9 | import lombok.Getter; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.io.File; 13 | import java.util.Arrays; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | @Getter 18 | public class SupplyConfig { 19 | 20 | private static final GunWar GUN_WAR = GunWar.getInstance(); 21 | 22 | private final String dirName; 23 | private final ImmutableMap pageConfigMap; 24 | private final ImmutableMap itemConfigMap; 25 | private SupplyPageConfig defaultPageConfig; 26 | 27 | public SupplyConfig(@NotNull String dirName, @NotNull File path) throws SupplyConfigLoadException { 28 | this.dirName = dirName; 29 | File[] childDir = path.listFiles(); 30 | if (childDir == null) { 31 | throw new SupplyConfigLoadException("加载" + dirName + "失败!"); 32 | } 33 | 34 | childDir = Arrays.stream(childDir).filter(File::isDirectory).toArray(File[]::new); 35 | 36 | if (childDir.length != 2 || !Arrays.asList("items", "pages").contains(childDir[0].getName()) || 37 | !Arrays.asList("items", "pages").contains(childDir[1].getName())) { 38 | throw new SupplyConfigLoadException("加载" + dirName + "失败!"); 39 | } 40 | File itemsPath = new File(path, "items"); 41 | File[] itemsFiles = itemsPath.listFiles(); 42 | File pagesPath = new File(path, "pages"); 43 | File[] pagesFiles = pagesPath.listFiles(); 44 | if (itemsFiles == null || pagesFiles == null) { 45 | throw new SupplyConfigLoadException("加载" + dirName + "失败!"); 46 | } 47 | 48 | ImmutableMap.Builder itemConfigMapBuilder = ImmutableMap.builder(); 49 | Arrays.stream(itemsFiles) 50 | .filter(this::checkItemFileCorrect) 51 | .forEach(itemFile -> { 52 | String fileName = itemFile.getName().split("\\.")[0]; 53 | try { 54 | itemConfigMapBuilder.put(fileName, new SupplyItemConfig(fileName, itemFile)); 55 | } catch (SupplyConfigLoadException e) { 56 | GunWar.getInstance().getLogger().error("SupplyItemConfig 加载错误!", e); 57 | } 58 | }); 59 | this.itemConfigMap = itemConfigMapBuilder.build(); 60 | 61 | ImmutableMap.Builder supplyPageConfigBuilder = ImmutableMap.builder(); 62 | Arrays.stream(pagesFiles) 63 | .filter(this::checkPageFileCorrect) 64 | .forEach(pageFile -> { 65 | String fileName = pageFile.getName().split("\\.")[0]; 66 | SupplyPageConfig pageConfig = new SupplyPageConfig(fileName, pageFile, this); 67 | supplyPageConfigBuilder.put(fileName, pageConfig); 68 | Config config = new Config(pageFile, 2); 69 | if (config.getBoolean("default", false)) { 70 | this.defaultPageConfig = pageConfig; 71 | } 72 | }); 73 | this.pageConfigMap = supplyPageConfigBuilder.build(); 74 | if (this.defaultPageConfig == null) { 75 | throw new SupplyConfigLoadException("商店供给:" + dirName + " 无默认界面!"); 76 | } 77 | } 78 | 79 | /** 80 | * @return 返回识别名称(文件夹名称) 81 | */ 82 | public String getName() { 83 | return dirName; 84 | } 85 | 86 | private boolean checkItemFileCorrect(File file) { 87 | if (!file.getName().endsWith(".yml")) { 88 | return false; 89 | } 90 | Config config = new Config(file, Config.YAML); 91 | List authorizedKey = Arrays.asList("title", "subTitle", "items", "needIntegral", "pos"); 92 | for (String necessary : authorizedKey) { 93 | if (!config.exists(necessary)) { 94 | return false; 95 | } 96 | } 97 | return true; 98 | } 99 | 100 | private boolean checkPageFileCorrect(File file) { 101 | if (!file.getName().endsWith(".yml")) { 102 | return false; 103 | } 104 | Config config = new Config(file, 2); 105 | List authorizedKey = Arrays.asList("title", "linkItems", "items", "default"); 106 | if (config.getAll().keySet().size() != authorizedKey.size() && 107 | (config.getAll().containsKey("linkItem") || config.getAll().containsKey("default"))) { 108 | return false; 109 | } 110 | for (Map.Entry entry : config.getAll().entrySet()) { 111 | if (!authorizedKey.contains(entry.getKey())) { 112 | return false; 113 | } 114 | } 115 | return true; 116 | } 117 | 118 | } -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/command/usersub/JoinCommand.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.command.usersub; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.lanink.gunwar.command.base.BaseSubCommand; 5 | import cn.lanink.gunwar.room.base.BaseRoom; 6 | import cn.lanink.teamsystem.TeamSystem; 7 | import cn.lanink.teamsystem.team.Team; 8 | import cn.nukkit.Player; 9 | import cn.nukkit.command.CommandSender; 10 | import cn.nukkit.command.data.CommandParamType; 11 | import cn.nukkit.command.data.CommandParameter; 12 | 13 | import java.util.LinkedList; 14 | 15 | public class JoinCommand extends BaseSubCommand { 16 | 17 | public JoinCommand(String name) { 18 | super(name); 19 | } 20 | 21 | @Override 22 | public boolean canUser(CommandSender sender) { 23 | return sender.isPlayer(); 24 | } 25 | 26 | @Override 27 | public String[] getAliases() { 28 | return new String[] { "加入" }; 29 | } 30 | 31 | @Override 32 | public boolean execute(CommandSender sender, String label, String[] args) { 33 | Player player = (Player) sender; 34 | if (this.gunWar.getGameRoomManager().getGameRoomMap().size() > 0) { 35 | if (player.riding != null) { 36 | sender.sendMessage(this.language.translateString("joinRoomIsRiding")); 37 | return true; 38 | } 39 | for (BaseRoom room : this.gunWar.getGameRoomManager().getGameRoomMap().values()) { 40 | if (room.isPlaying(player)) { 41 | sender.sendMessage(this.language.translateString("joinRoomIsInRoom")); 42 | return true; 43 | } 44 | } 45 | 46 | if (this.gunWar.isHasTeamSystem()) { 47 | Team team = TeamSystem.Companion.getTeamByPlayer(player); 48 | if (team != null) { 49 | if (!team.isTeamLeader(player)) { 50 | sender.sendMessage("[GunWar-TeamSystem] 你不是队长,无法主动加入游戏!"); 51 | sender.sendMessage("[GunWar-TeamSystem] 请让队长加入游戏或先退出队伍!!"); 52 | return true; 53 | } 54 | if (!team.isAllMemberOnline()) { 55 | //TODO 当TeamSystem支持后,尝试传送玩家到当前服务器 56 | sender.sendMessage("[GunWar-TeamSystem] 队伍中有玩家不在线,无法加入游戏!"); 57 | return true; 58 | } 59 | } 60 | } 61 | 62 | if (args.length < 2) { 63 | BaseRoom room = this.gunWar.getGameRoomManager().getCanJoinGameRoom(player); 64 | if (room != null) { 65 | room.joinRoom(player); 66 | sender.sendMessage(this.language.translateString("joinRandomRoom")); 67 | return true; 68 | } 69 | }else { 70 | String[] s = args[1].split(":"); 71 | if (s.length == 2 && s[0].toLowerCase().trim().equals("mode")) { 72 | String modeName = s[1].toLowerCase().trim(); 73 | LinkedList rooms = new LinkedList<>(); 74 | for (BaseRoom room : this.gunWar.getGameRoomManager().getCanJoinGameRoomList(modeName)) { 75 | if (room.canJoin(player)) { 76 | if (room.getPlayerDataMap().size() > 0) { 77 | room.joinRoom(player); 78 | sender.sendMessage(this.language.translateString("joinRandomRoom")); 79 | return true; 80 | } 81 | rooms.add(room); 82 | } 83 | } 84 | if (rooms.size() > 0) { 85 | BaseRoom room = rooms.get(GunWar.RANDOM.nextInt(rooms.size())); 86 | room.joinRoom(player); 87 | sender.sendMessage(this.language.translateString("joinRandomRoom")); 88 | return true; 89 | } 90 | sender.sendMessage(this.language.translateString("joinRoomIsNotFound")); 91 | return true; 92 | }else if (this.gunWar.getGameRoomManager().hasGameRoom(args[1])) { 93 | BaseRoom room = this.gunWar.getGameRoomManager().getGameRoom(args[1]); 94 | if (room.getStatus() != 0 && room.getStatus() != 1) { 95 | sender.sendMessage(this.language.translateString("joinRoomIsPlaying")); 96 | } else if (room.getPlayerDataMap().size() >= room.getMaxPlayers()) { 97 | sender.sendMessage(this.language.translateString("joinRoomIsFull")); 98 | } else { 99 | room.joinRoom(player); 100 | } 101 | return true; 102 | } else { 103 | sender.sendMessage(this.language.translateString("joinRoomIsNotFound")); 104 | return true; 105 | } 106 | } 107 | } 108 | sender.sendMessage(this.language.translateString("joinRoomNotAvailable")); 109 | return true; 110 | } 111 | 112 | @Override 113 | public CommandParameter[] getParameters() { 114 | return new CommandParameter[] { new CommandParameter("roomName", CommandParamType.TEXT, false) }; 115 | } 116 | 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/item/weapon/GunWeapon.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.item.weapon; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.lanink.gunwar.entity.bullet.BulletSnowBall; 5 | import cn.lanink.gunwar.item.ItemManage; 6 | import cn.lanink.gunwar.tasks.GunReloadTask; 7 | import cn.nukkit.Player; 8 | import cn.nukkit.Server; 9 | import cn.nukkit.level.ParticleEffect; 10 | import cn.nukkit.math.Vector3; 11 | import cn.nukkit.nbt.tag.CompoundTag; 12 | import cn.nukkit.scheduler.PluginTask; 13 | import cn.nukkit.scheduler.Task; 14 | import cn.nukkit.utils.Config; 15 | import org.jetbrains.annotations.NotNull; 16 | 17 | import java.util.concurrent.ConcurrentHashMap; 18 | 19 | /** 20 | * @author lt_name 21 | */ 22 | public class GunWeapon extends BaseWeapon { 23 | 24 | protected int maxMagazine; 25 | protected float gravity; 26 | protected float motionMultiply; 27 | protected float reloadTime; 28 | protected boolean reloadInterrupted; 29 | protected ParticleEffect particleEffect; 30 | 31 | protected ConcurrentHashMap magazineMap = new ConcurrentHashMap<>(); 32 | protected ConcurrentHashMap reloadTask = new ConcurrentHashMap<>(); 33 | 34 | public GunWeapon(String name, Config config) { 35 | super(name, config); 36 | this.item.getNamedTag().putByte("Unbreakable", 1); 37 | this.maxMagazine = config.getInt("maxMagazine"); 38 | this.gravity = (float) config.getDouble("gravity"); 39 | this.motionMultiply = (float) config.getDouble("motionMultiply"); 40 | this.reloadTime = (float) config.getDouble("reloadTime"); 41 | this.reloadInterrupted = config.getBoolean("reloadInterrupted"); 42 | String stringParticleEffect = config.getString("particleEffect").trim(); 43 | if (!"".equals(stringParticleEffect)) { 44 | this.particleEffect = ParticleEffect.valueOf(stringParticleEffect); 45 | } 46 | 47 | CompoundTag tag = this.getCompoundTag(); 48 | tag.putInt("maxMagazine", this.maxMagazine) 49 | .putFloat("gravity", this.gravity) 50 | .putFloat("motionMultiply", this.motionMultiply) 51 | .putFloat("reloadTime", this.reloadTime) 52 | .putBoolean("reloadInterrupted", this.reloadInterrupted); 53 | this.setCompoundTag(tag); 54 | } 55 | 56 | @Override 57 | public ItemManage.ItemType getItemType() { 58 | return ItemManage.ItemType.WEAPON_GUN; 59 | } 60 | 61 | /** 62 | * @return 弹匣容量 63 | */ 64 | public int getMaxMagazine() { 65 | return this.maxMagazine; 66 | } 67 | 68 | /** 69 | * @return 装填时间 70 | */ 71 | public float getReloadTime() { 72 | return this.reloadTime; 73 | } 74 | 75 | public boolean isReloadInterrupted() { 76 | return this.reloadInterrupted; 77 | } 78 | 79 | /** 80 | * @return 重力 81 | */ 82 | public float getGravity() { 83 | return this.gravity; 84 | } 85 | 86 | public float getMotionMultiply() { 87 | return this.motionMultiply; 88 | } 89 | 90 | public ParticleEffect getParticleEffect() { 91 | return this.particleEffect; 92 | } 93 | 94 | public ConcurrentHashMap getMagazineMap() { 95 | return this.magazineMap; 96 | } 97 | 98 | public int getMagazine(Player player) { 99 | return this.magazineMap.getOrDefault(player, 0); 100 | } 101 | 102 | public void resetStatus(@NotNull Player player) { 103 | this.stopReload(player); 104 | this.magazineMap.remove(player); 105 | } 106 | 107 | public int shooting(Player player, Vector3 directionVector) { 108 | int bullets = this.magazineMap.getOrDefault(player, this.getMaxMagazine()); 109 | if (bullets > 0) { 110 | if (!this.isReload(player) || this.isReloadInterrupted()) { 111 | this.stopReload(player); 112 | BulletSnowBall.launch( 113 | player, 114 | directionVector, 115 | this.getGravity(), 116 | this.getMotionMultiply(), 117 | this.getParticleEffect(), 118 | this.getCompoundTag()); 119 | this.magazineMap.put(player, --bullets); 120 | } 121 | } 122 | if (bullets <= 0) { 123 | this.startReload(player); 124 | } 125 | return bullets; 126 | } 127 | 128 | public ConcurrentHashMap getReloadTask() { 129 | return this.reloadTask; 130 | } 131 | 132 | public boolean isReload(Player player) { 133 | return this.reloadTask.containsKey(player); 134 | } 135 | 136 | public void startReload(Player player) { 137 | if (this.getMagazine(player) < this.getMaxMagazine() && 138 | !this.reloadTask.containsKey(player)) { 139 | PluginTask task = new GunReloadTask( 140 | player, this, (this.getMaxMagazine() / this.getReloadTime())); 141 | Server.getInstance().getScheduler().scheduleRepeatingTask(task, 1, true); 142 | this.reloadTask.put(player, task); 143 | } 144 | } 145 | 146 | public void stopReload(Player player) { 147 | if (this.isReload(player)) { 148 | this.reloadTask.get(player).cancel(); 149 | this.reloadTask.remove(player); 150 | } 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/utils/gamerecord/RankingManager.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.utils.gamerecord; 2 | 3 | import cn.lanink.gamecore.ranking.Ranking; 4 | import cn.lanink.gamecore.ranking.RankingAPI; 5 | import cn.lanink.gamecore.ranking.RankingFormat; 6 | import cn.lanink.gunwar.GunWar; 7 | import cn.lanink.gunwar.utils.Tools; 8 | import cn.nukkit.Server; 9 | import cn.nukkit.level.Position; 10 | import cn.nukkit.utils.Config; 11 | import lombok.AllArgsConstructor; 12 | import lombok.Data; 13 | import lombok.Getter; 14 | 15 | import java.util.*; 16 | 17 | /** 18 | * 排行榜管理 19 | * 20 | * @author LT_Name 21 | */ 22 | public class RankingManager { 23 | 24 | @Getter 25 | private static final ArrayList RANKING_DATA_LIST = new ArrayList<>(); 26 | @Getter 27 | private static final HashMap RANKING_MAP = new HashMap<>(); 28 | 29 | /** 30 | * 加载排行榜 (可当reload用) 31 | */ 32 | public static void load() { 33 | clear(); 34 | 35 | //读取排行榜数据 36 | Config rankingConfig = new Config(GunWar.getInstance().getDataFolder() + "/RankingConfig.yml", Config.YAML); 37 | //加载排行榜格式 38 | RankingFormat rankingFormat = RankingFormat.getDefaultFormat(); 39 | rankingFormat.setTop(rankingConfig.getString("RankingFormat.Top")); 40 | rankingFormat.setLine(rankingConfig.getString("RankingFormat.Line")); 41 | rankingFormat.setLineSelf(rankingConfig.getString("RankingFormat.LineSelf")); 42 | rankingFormat.setBottom(rankingConfig.getString("RankingFormat.Bottom")); 43 | try { //ShowLine 配置不好很容易出错,这里捕获下 44 | if (rankingConfig.exists("RankingFormat.ShowLine")) { 45 | Map map = (Map) rankingConfig.get("RankingFormat.ShowLine"); 46 | rankingFormat.getShowLine().clear(); 47 | for (Map.Entry entry : map.entrySet()) { 48 | rankingFormat.getShowLine().put(Integer.parseInt(entry.getKey()), entry.getValue()); 49 | } 50 | } 51 | }catch (Exception e) { 52 | GunWar.getInstance().getLogger().error("加载排行榜格式失败!请检查配置文件!", e); 53 | } 54 | 55 | List list = rankingConfig.getMapList("pos"); 56 | for (Map map : list) { 57 | try { 58 | String levelName = (String) map.get("level"); 59 | if (!Server.getInstance().loadLevel(levelName)) { 60 | throw new RuntimeException("世界:" + levelName + " 加载失败!"); 61 | } 62 | String stringType = (String) map.get("type"); 63 | RecordType type = RecordType.of(stringType); 64 | if (type == null) { 65 | throw new RuntimeException("排行榜类型:" + stringType + " 不存在!"); 66 | } 67 | RANKING_DATA_LIST.add( 68 | new RankingData( 69 | (String) map.get("name"), 70 | type, 71 | Position.fromObject(Tools.mapToVector3(map), Server.getInstance().getLevelByName(levelName)) 72 | ) 73 | ); 74 | } catch (Exception e) { 75 | GunWar.getInstance().getLogger().error("读取排行榜数据出错! 配置: " + map, e); 76 | } 77 | } 78 | if (GunWar.debug) { 79 | GunWar.getInstance().getLogger().info("[debug] " + RANKING_DATA_LIST); 80 | } 81 | //创建排行榜 82 | for (RankingData rankingData : RANKING_DATA_LIST) { 83 | Ranking ranking = RankingAPI.createRanking(GunWar.getInstance(), rankingData.getName(), rankingData.getPosition()); 84 | ranking.setRankingList(() -> GameRecord.getRankingList(rankingData.getType())); 85 | ranking.setRankingFormat(rankingFormat); 86 | RANKING_MAP.put(rankingData.getName(), ranking); 87 | } 88 | GunWar.getInstance().getLogger().info("排行榜加载完成!成功创建 " + RANKING_MAP.size() + " 个排行榜!"); 89 | } 90 | 91 | public static void addRanking(RankingData rankingData) { 92 | RANKING_DATA_LIST.add(rankingData); 93 | } 94 | 95 | /** 96 | * 保存排行榜数据 97 | */ 98 | public static void save() { 99 | ArrayList> list = new ArrayList<>(); 100 | for (RankingData rankingData : RANKING_DATA_LIST) { 101 | LinkedHashMap map = new LinkedHashMap<>(); 102 | map.put("name", rankingData.getName()); 103 | map.put("type", rankingData.getType().getName()); 104 | map.putAll(Tools.vector3ToMap(rankingData.getPosition())); 105 | map.put("level", rankingData.getPosition().getLevel().getFolderName()); 106 | list.add(map); 107 | } 108 | Config rankingConfig = new Config(GunWar.getInstance().getDataFolder() + "/RankingConfig.yml", Config.YAML); 109 | rankingConfig.set("pos", list); 110 | rankingConfig.save(); 111 | } 112 | 113 | /** 114 | * 清理已加载的排行榜 115 | */ 116 | public static void clear() { 117 | RANKING_DATA_LIST.clear(); 118 | if (!RANKING_MAP.isEmpty()) { 119 | for (Ranking ranking : RANKING_MAP.values()) { 120 | ranking.close(); 121 | } 122 | RANKING_MAP.clear(); 123 | } 124 | } 125 | 126 | @AllArgsConstructor 127 | @Data 128 | public static class RankingData { 129 | private String name; 130 | private RecordType type; 131 | private Position position; 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/tasks/game/conquest/AsyncFlagRadiusCheckTask.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.tasks.game.conquest; 2 | 3 | import cn.lanink.gamecore.room.IRoomStatus; 4 | import cn.lanink.gunwar.GunWar; 5 | import cn.lanink.gunwar.entity.flag.EntityLongFlag; 6 | import cn.lanink.gunwar.room.base.Team; 7 | import cn.lanink.gunwar.room.conquest.ConquestModeRoom; 8 | import cn.lanink.gunwar.utils.Tools; 9 | import cn.nukkit.Player; 10 | import cn.nukkit.block.BlockID; 11 | import cn.nukkit.level.ParticleEffect; 12 | import cn.nukkit.math.Vector3; 13 | import cn.nukkit.scheduler.AsyncTask; 14 | 15 | import java.util.ArrayList; 16 | import java.util.HashMap; 17 | import java.util.LinkedList; 18 | 19 | /** 20 | * 用粒子直观显示占领旗帜有效范围 21 | * 22 | * @author LT_Name 23 | */ 24 | public class AsyncFlagRadiusCheckTask extends AsyncTask { 25 | 26 | private int tick = 0; 27 | private final ConquestModeRoom room; 28 | private final HashMap playerLastIn = new HashMap<>(); 29 | 30 | public AsyncFlagRadiusCheckTask(ConquestModeRoom room) { 31 | this.room = room; 32 | } 33 | 34 | @Override 35 | public void onRun() { 36 | long startTime; 37 | while (this.room.getStatus() == IRoomStatus.ROOM_STATUS_GAME) { 38 | startTime = System.currentTimeMillis(); 39 | 40 | try { 41 | this.work(this.tick); 42 | } catch (Exception e) { 43 | GunWar.getInstance().getLogger().error("AsyncFlagRadiusCheckTask Error!", e); 44 | } 45 | 46 | this.tick++; 47 | 48 | long duration = System.currentTimeMillis() - startTime; 49 | try { 50 | Thread.sleep(Math.max(50L - duration, 1)); 51 | } catch (Exception e) { 52 | GunWar.getInstance().getLogger().error("AsyncFlagRadiusCheckTask Error!", e); 53 | } 54 | } 55 | } 56 | 57 | private void work(int tick) { 58 | ArrayList aFlagPlayers = new ArrayList<>(); 59 | ArrayList bFlagPlayers = new ArrayList<>(); 60 | ArrayList cFlagPlayers = new ArrayList<>(); 61 | for (Player player : this.room.getPlayerDataMap().keySet()) { 62 | if (player.distance(this.room.getConquestPointA()) <= this.room.getConquestPointRadius()) { 63 | aFlagPlayers.add(player); 64 | }else if (player.distance(this.room.getConquestPointB()) <= this.room.getConquestPointRadius()) { 65 | bFlagPlayers.add(player); 66 | }else if (player.distance(this.room.getConquestPointC()) <= this.room.getConquestPointRadius()) { 67 | cFlagPlayers.add(player); 68 | } 69 | } 70 | this.checkCapturePoints(aFlagPlayers, this.room.flagA); 71 | this.checkCapturePoints(bFlagPlayers, this.room.flagB); 72 | this.checkCapturePoints(cFlagPlayers, this.room.flagC); 73 | 74 | if (tick%20 == 1) { 75 | this.showParticleEffect(); 76 | } 77 | } 78 | 79 | /** 80 | * 检查旗帜占领进度 81 | * 82 | * @param players 在占领范围内的玩家列表 83 | * @param flag 旗帜 84 | */ 85 | private void checkCapturePoints(ArrayList players, EntityLongFlag flag) { 86 | ArrayList redCount = new ArrayList<>(); 87 | ArrayList blueCount = new ArrayList<>(); 88 | for (Player player : players) { 89 | int last = this.playerLastIn.getOrDefault(player, tick); 90 | if (tick - last >= 1) { 91 | Team playerTeam = this.room.getPlayerTeamAccurate(player); 92 | if (playerTeam == Team.RED) { 93 | redCount.add(player); 94 | }else if (playerTeam == Team.BLUE) { 95 | blueCount.add(player); 96 | } 97 | } 98 | this.playerLastIn.put(player, tick); 99 | } 100 | if (redCount.size() > blueCount.size()) { 101 | flag.addTeamPoints(Team.RED, (redCount.size() - blueCount.size())); 102 | }else if (blueCount.size() > redCount.size()) { 103 | flag.addTeamPoints(Team.BLUE, (blueCount.size() - redCount.size())); 104 | } 105 | } 106 | 107 | /** 108 | * 显示占领范围粒子效果 109 | */ 110 | private void showParticleEffect() { 111 | LinkedList list = Tools.getRoundEdgePoint(this.room.getConquestPointA(), this.room.getConquestPointRadius()); 112 | list.addAll(Tools.getRoundEdgePoint(this.room.getConquestPointB(), this.room.getConquestPointRadius())); 113 | list.addAll(Tools.getRoundEdgePoint(this.room.getConquestPointC(), this.room.getConquestPointRadius())); 114 | for (Vector3 vector3 : list) { 115 | vector3.y += 0.1; 116 | if (this.room.getLevel().getBlock(vector3).getId() == BlockID.AIR) { 117 | for (int y = vector3.getFloorY(); y > y - 5; y--) { 118 | if (this.room.getLevel().getBlock(new Vector3(vector3.x, y, vector3.z)).getId() != BlockID.AIR) { 119 | vector3.y = y + 1.1; 120 | break; 121 | } 122 | } 123 | } else { 124 | for (int y = vector3.getFloorY(); y < y + 5; y++) { 125 | if (this.room.getLevel().getBlock(new Vector3(vector3.x, y, vector3.z)).getId() == BlockID.AIR) { 126 | vector3.y = y + 0.1; 127 | break; 128 | } 129 | } 130 | } 131 | this.room.getLevel().addParticleEffect(vector3, ParticleEffect.REDSTONE_TORCH_DUST); 132 | } 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/tasks/VictoryTask.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.tasks; 2 | 3 | import cn.lanink.gamecore.utils.Language; 4 | import cn.lanink.gunwar.GunWar; 5 | import cn.lanink.gunwar.room.base.BaseRoom; 6 | import cn.lanink.gunwar.room.base.PlayerGameData; 7 | import cn.lanink.gunwar.room.base.Team; 8 | import cn.lanink.gunwar.utils.Tools; 9 | import cn.lanink.gunwar.utils.gamerecord.GameRecord; 10 | import cn.lanink.gunwar.utils.gamerecord.RecordType; 11 | import cn.nukkit.Player; 12 | import cn.nukkit.scheduler.PluginTask; 13 | 14 | import java.util.LinkedList; 15 | import java.util.Map; 16 | 17 | 18 | public class VictoryTask extends PluginTask { 19 | 20 | private final Language language; 21 | private final BaseRoom room; 22 | private int victoryTime; 23 | private int victory = 0; 24 | private Player victoryPlayer; 25 | 26 | public VictoryTask(GunWar owner, BaseRoom room, int victory) { 27 | this(owner, room); 28 | 29 | this.victory = victory; 30 | 31 | for (Map.Entry entry: room.getPlayerDataMap().entrySet()) { 32 | LinkedList ms = new LinkedList<>(); 33 | switch (this.victory) { 34 | case 1: 35 | if (entry.getValue().getTeam() == Team.RED || entry.getValue().getTeam() == Team.RED_DEATH) { 36 | GameRecord.addPlayerRecord(entry.getKey(), RecordType.VICTORY); 37 | }else { 38 | GameRecord.addPlayerRecord(entry.getKey(), RecordType.DEFEAT); 39 | } 40 | ms.add(this.language.translateString("victoryMessage", 41 | this.language.translateString("teamNameRed"))); 42 | owner.getScoreboard().showScoreboard(entry.getKey(), this.language.translateString("scoreBoardTitle"), ms); 43 | entry.getKey().sendTitle(this.language.translateString("victoryRed"), "", 10, 40, 20); 44 | break; 45 | case 2: 46 | if (entry.getValue().getTeam() == Team.BLUE || entry.getValue().getTeam() == Team.BLUE_DEATH) { 47 | GameRecord.addPlayerRecord(entry.getKey(), RecordType.VICTORY); 48 | }else { 49 | GameRecord.addPlayerRecord(entry.getKey(), RecordType.DEFEAT); 50 | } 51 | ms.add(this.language.translateString("victoryMessage", 52 | this.language.translateString("teamNameBlue"))); 53 | owner.getScoreboard().showScoreboard(entry.getKey(), this.language.translateString("scoreBoardTitle"), ms); 54 | entry.getKey().sendTitle(this.language.translateString("victoryBlue"), "", 10, 40, 20); 55 | break; 56 | default: 57 | ms.add(this.language.translateString("game_ctf_draw")); 58 | owner.getScoreboard().showScoreboard(entry.getKey(), this.language.translateString("scoreBoardTitle"), ms); 59 | entry.getKey().sendTitle(this.language.translateString("game_ctf_draw"), "", 10, 40, 20); 60 | break; 61 | } 62 | } 63 | } 64 | 65 | public VictoryTask(GunWar owner, BaseRoom room, Player victory) { 66 | this(owner, room); 67 | 68 | this.victoryPlayer = victory; 69 | 70 | for (Map.Entry entry: room.getPlayerDataMap().entrySet()) { 71 | LinkedList ms = new LinkedList<>(); 72 | if (entry.getKey() == this.victoryPlayer) { 73 | GameRecord.addPlayerRecord(entry.getKey(), RecordType.VICTORY); 74 | }else { 75 | GameRecord.addPlayerRecord(entry.getKey(), RecordType.DEFEAT); 76 | } 77 | ms.add(this.language.translateString("victoryMessage", this.victoryPlayer.getName())); 78 | owner.getScoreboard().showScoreboard(entry.getKey(), this.language.translateString("scoreBoardTitle"), ms); 79 | } 80 | } 81 | 82 | private VictoryTask(GunWar owner, BaseRoom room) { 83 | super(owner); 84 | this.language = owner.getLanguage(); 85 | this.room = room; 86 | this.victoryTime = 10; 87 | } 88 | 89 | @Override 90 | public void onRun(int i) { 91 | if (this.room.getStatus() != 3) { 92 | this.cancel(); 93 | return; 94 | } 95 | if (this.victoryTime < 1) { 96 | this.room.endGame(this.victory); 97 | this.cancel(); 98 | }else { 99 | this.victoryTime--; 100 | if (!this.room.getPlayerDataMap().isEmpty()) { 101 | for (Map.Entry entry : room.getPlayerDataMap().entrySet()) { 102 | if (this.victoryPlayer != null) { 103 | entry.getKey().sendTip(this.language.translateString("victoryMessage", this.victoryPlayer.getName())); 104 | Tools.spawnFirework(this.victoryPlayer); 105 | }else if (entry.getValue().getTeam() != Team.NULL) { 106 | if (this.victory == 1) { 107 | entry.getKey().sendTip(this.language.translateString("victoryMessage", 108 | this.language.translateString("teamNameRed"))); 109 | if (entry.getValue().getTeam() == Team.RED) { 110 | Tools.spawnFirework(entry.getKey()); 111 | } 112 | }else if (this.victory == 2) { 113 | entry.getKey().sendTip(this.language.translateString("victoryMessage", 114 | this.language.translateString("teamNameBlue"))); 115 | if (entry.getValue().getTeam() == Team.BLUE) { 116 | Tools.spawnFirework(entry.getKey()); 117 | } 118 | }else { 119 | entry.getKey().sendTip(this.language.translateString("game_ctf_draw")); 120 | } 121 | } 122 | } 123 | } 124 | } 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/cn/lanink/gunwar/entity/flag/EntityLongFlag.java: -------------------------------------------------------------------------------- 1 | package cn.lanink.gunwar.entity.flag; 2 | 3 | import cn.lanink.gunwar.GunWar; 4 | import cn.lanink.gunwar.room.base.Team; 5 | import cn.lanink.gunwar.utils.FlagSkinType; 6 | import cn.lanink.gunwar.utils.Tools; 7 | import cn.nukkit.entity.EntityHuman; 8 | import cn.nukkit.entity.data.Skin; 9 | import cn.nukkit.level.format.FullChunk; 10 | import cn.nukkit.nbt.tag.CompoundTag; 11 | import lombok.Getter; 12 | import lombok.Setter; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | /** 16 | * @author LT_Name 17 | */ 18 | public class EntityLongFlag extends EntityHuman { 19 | 20 | @Getter 21 | private Team team; 22 | 23 | private EntityFlagStand entityFlagStand; 24 | private EntityFlagHead entityFlagHead; 25 | 26 | @Getter 27 | private int flagHeight = 100; 28 | 29 | @Setter 30 | @Getter 31 | private int keepTime = 0; 32 | 33 | @Override 34 | public float getHeight() { 35 | return 2.5F; 36 | } 37 | 38 | @Override 39 | public float getLength() { 40 | return 0.3F; 41 | } 42 | 43 | @Override 44 | public float getWidth() { 45 | return 0.3F; 46 | } 47 | 48 | @Deprecated 49 | public EntityLongFlag(FullChunk chunk, CompoundTag nbt) { 50 | super(chunk, nbt); 51 | } 52 | 53 | public EntityLongFlag(FullChunk chunk, CompoundTag nbt, Team team) { 54 | super(chunk, nbt); 55 | this.setNameTagVisible(false); 56 | this.setNameTagAlwaysVisible(false); 57 | this.team = team; 58 | this.setSkin(GunWar.getInstance().getFlagSkin(FlagSkinType.LONG_FLAGPOLE)); 59 | this.spawnFlagStand(); 60 | this.setY(this.getY() + 0.4); 61 | this.spawnFlagHead(); 62 | } 63 | 64 | /** 65 | * 生成旗帜底座 66 | */ 67 | protected void spawnFlagStand() { 68 | Skin skin = GunWar.getInstance().getFlagSkin(getFlagStandSkinType()); 69 | CompoundTag tag = EntityFlagStand.getDefaultNBT(this); 70 | tag.putFloat("Scale", 1.0F); 71 | tag.putCompound("Skin", new CompoundTag() 72 | .putByteArray("Data", skin.getSkinData().data) 73 | .putString("ModelId", skin.getSkinId())); 74 | this.entityFlagStand = new EntityFlagStand(this.chunk, tag); 75 | this.entityFlagStand.setSkin(skin); 76 | this.entityFlagStand.spawnToAll(); 77 | } 78 | 79 | /** 80 | * 生成旗帜头实体 81 | */ 82 | protected void spawnFlagHead() { 83 | Skin headSkin = GunWar.getInstance().getFlagSkin(getFlagHeadSkinType()); 84 | CompoundTag tag = getDefaultNBT(this); 85 | tag.putFloat("Scale", 1.0F); 86 | tag.putCompound("Skin", new CompoundTag() 87 | .putByteArray("Data", headSkin.getSkinData().data) 88 | .putString("ModelId", headSkin.getSkinId())); 89 | this.entityFlagHead = new EntityFlagHead(this.chunk, tag); 90 | this.entityFlagHead.setSkin(headSkin); 91 | this.entityFlagHead.spawnToAll(); 92 | this.setFlagHeight(this.getFlagHeight()); 93 | } 94 | 95 | @Override 96 | public boolean onUpdate(int currentTick) { 97 | if (currentTick%20 == 0) { 98 | this.keepTime++; 99 | } 100 | return super.onUpdate(currentTick); 101 | } 102 | 103 | public void setTeam(Team team) { 104 | this.keepTime = 0; 105 | this.team = team; 106 | if (this.entityFlagStand != null) { 107 | Tools.setHumanSkin(this.entityFlagStand, GunWar.getInstance().getFlagSkin(getFlagStandSkinType())); 108 | } 109 | if (this.entityFlagHead != null) { 110 | Tools.setHumanSkin(this.entityFlagHead, GunWar.getInstance().getFlagSkin(getFlagHeadSkinType())); 111 | } 112 | } 113 | 114 | /** 115 | * 按比例设置旗帜头高度 116 | * 117 | * @param height 旗帜头高度(1-100) 118 | */ 119 | public void setFlagHeight(int height) { 120 | this.flagHeight = Math.min(100, Math.max(0, height)); 121 | this.entityFlagHead.setY(this.getY() + this.getHeight() * this.flagHeight/100f); 122 | } 123 | 124 | public void addTeamPoints(Team team, int points) { 125 | if (team == this.getTeam()) { 126 | if (this.getFlagHeight() < 100) { 127 | this.setFlagHeight(this.getFlagHeight() + points); 128 | } 129 | }else { 130 | if (this.getFlagHeight() > 0) { 131 | this.setFlagHeight(this.getFlagHeight() - points); 132 | }else { 133 | this.setTeam(team); 134 | } 135 | } 136 | } 137 | 138 | @Override 139 | public void close() { 140 | super.close(); 141 | if (this.entityFlagStand != null) { 142 | this.entityFlagStand.close(); 143 | } 144 | if (this.entityFlagHead != null) { 145 | this.entityFlagHead.close(); 146 | } 147 | } 148 | 149 | @NotNull 150 | private FlagSkinType getFlagStandSkinType() { 151 | FlagSkinType skinType; 152 | switch (this.team) { 153 | case RED: 154 | case RED_DEATH: 155 | skinType = FlagSkinType.FLAG_STAND_RED; 156 | break; 157 | case BLUE: 158 | case BLUE_DEATH: 159 | skinType = FlagSkinType.FLAG_STAND_BLUE; 160 | break; 161 | case NULL: 162 | default: 163 | skinType = FlagSkinType.FLAG_STAND_WHITE; 164 | break; 165 | } 166 | return skinType; 167 | } 168 | 169 | @NotNull 170 | private FlagSkinType getFlagHeadSkinType() { 171 | FlagSkinType skinType; 172 | switch (this.team) { 173 | case RED: 174 | case RED_DEATH: 175 | skinType = FlagSkinType.FLAG_HEAD_RED; 176 | break; 177 | case BLUE: 178 | case BLUE_DEATH: 179 | skinType = FlagSkinType.FLAG_HEAD_BLUE; 180 | break; 181 | case NULL: 182 | default: 183 | skinType = FlagSkinType.FLAG_HEAD_WHITE; 184 | break; 185 | } 186 | return skinType; 187 | } 188 | 189 | public static class EntityFlagHead extends EntityHuman { 190 | 191 | public EntityFlagHead(FullChunk chunk, CompoundTag nbt) { 192 | super(chunk, nbt); 193 | } 194 | 195 | @Override 196 | public float getHeight() { 197 | return 0.01F; 198 | } 199 | 200 | @Override 201 | public float getLength() { 202 | return 0.01F; 203 | } 204 | 205 | @Override 206 | public float getWidth() { 207 | return 0.01F; 208 | } 209 | 210 | } 211 | 212 | } 213 | --------------------------------------------------------------------------------