/createNPC command #37

This commit is contained in:
Ziggy
2020-11-15 18:45:38 +01:00
parent 1b5e16e748
commit bed859c8c4
10 changed files with 661 additions and 33 deletions

View File

@@ -0,0 +1,47 @@
/***********************************************************************************
* Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
* *
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
* Our goal is to create an emulator which will provide a server for players to *
* continue playing a game similar to the one they used to play. We are basing *
* it on the final publish of the game prior to end-game events. *
* *
* This file is part of Holocore. *
* *
* --------------------------------------------------------------------------------*
* *
* Holocore is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* Holocore is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
***********************************************************************************/
package com.projectswg.holocore.intents.gameplay.world.spawn;
import com.projectswg.holocore.resources.support.npc.spawn.SpawnInfo;
import me.joshlarson.jlcommon.control.Intent;
import org.jetbrains.annotations.NotNull;
public class CreateSpawnIntent extends Intent {
private final SpawnInfo spawnInfo;
private CreateSpawnIntent(@NotNull SpawnInfo spawnInfo) {
this.spawnInfo = spawnInfo;
}
public SpawnInfo getSpawnInfo() {
return spawnInfo;
}
public static void broadcast(@NotNull SpawnInfo spawnInfo) {
new CreateSpawnIntent(spawnInfo).broadcast();
}
}

View File

@@ -30,6 +30,7 @@ import com.projectswg.common.data.location.Terrain;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet;
import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader;
import com.projectswg.holocore.resources.support.npc.spawn.SpawnInfo;
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureDifficulty;
import com.projectswg.holocore.resources.support.objects.swg.custom.AIBehavior;
import me.joshlarson.jlcommon.log.Log;
@@ -71,7 +72,7 @@ public final class NpcStaticSpawnLoader extends DataLoader {
INVULNERABLE
}
public static class StaticSpawnInfo {
public static class StaticSpawnInfo implements SpawnInfo {
private final String id;
private final Terrain terrain;
@@ -146,90 +147,112 @@ public final class NpcStaticSpawnLoader extends DataLoader {
}
}
@Override
public String getId() {
return id;
}
@Override
public Terrain getTerrain() {
return terrain;
}
@Override
public double getX() {
return x;
}
@Override
public double getY() {
return y;
}
@Override
public double getZ() {
return z;
}
@Override
public int getHeading() {
return heading;
}
@Override
public int getCellId() {
return cellId;
}
@Override
public String getSpawnerType() {
return spawnerType;
}
@Override
public String getNpcId() {
return npcId;
}
@Override
public SpawnerFlag getSpawnerFlag() {
return spawnerFlag;
}
@Override
public CreatureDifficulty getDifficulty() {
return difficulty;
}
@Override
public int getMinLevel() {
return minLevel;
}
@Override
public int getMaxLevel() {
return maxLevel;
}
@Override
public String getBuildingId() {
return buildingId;
}
@Override
public String getMood() {
return mood;
}
@Override
public AIBehavior getBehavior() {
return behavior;
}
@Override
public String getPatrolId() {
return patrolId;
}
@Override
public PatrolFormation getPatrolFormation() {
return patrolFormation;
}
@Override
public int getLoiterRadius() {
return loiterRadius;
}
@Override
public int getMinSpawnTime() {
return minSpawnTime;
}
@Override
public int getMaxSpawnTime() {
return maxSpawnTime;
}
@Override
public int getAmount() {
return amount;
}

View File

@@ -0,0 +1,117 @@
/***********************************************************************************
* Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
* *
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
* Our goal is to create an emulator which will provide a server for players to *
* continue playing a game similar to the one they used to play. We are basing *
* it on the final publish of the game prior to end-game events. *
* *
* This file is part of Holocore. *
* *
* --------------------------------------------------------------------------------*
* *
* Holocore is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* Holocore is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
***********************************************************************************/
package com.projectswg.holocore.resources.support.global.commands.callbacks.admin;
import com.projectswg.holocore.intents.gameplay.world.spawn.CreateSpawnIntent;
import com.projectswg.holocore.intents.support.global.chat.SystemMessageIntent;
import com.projectswg.holocore.resources.support.data.server_info.loader.npc.NpcStaticSpawnLoader;
import com.projectswg.holocore.resources.support.global.commands.ICmdCallback;
import com.projectswg.holocore.resources.support.global.player.AccessLevel;
import com.projectswg.holocore.resources.support.global.player.Player;
import com.projectswg.holocore.resources.support.npc.spawn.SimpleSpawnInfo;
import com.projectswg.holocore.resources.support.npc.spawn.SpawnerType;
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
import com.projectswg.holocore.resources.support.objects.swg.cell.CellObject;
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureDifficulty;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class CmdCreateNpc implements ICmdCallback {
@Override
public void execute(@NotNull Player player, @Nullable SWGObject target, @NotNull String args) {
if (player.getAccessLevel() == AccessLevel.PLAYER) {
SystemMessageIntent.broadcastPersonal(player, "Players cannot use this command :(");
return;
}
String[] commandArgs = args.split(" ");
String npcId = determineNpcId(commandArgs);
CreatureDifficulty difficulty = determineDifficulty(commandArgs);
int combatLevel = determineCombatLevel(commandArgs);
spawnNPC(player, npcId, difficulty, combatLevel);
}
private String determineNpcId(String[] commandArgs) {
return commandArgs[0];
}
private CreatureDifficulty determineDifficulty(String[] commandArgs) {
String arg = commandArgs[1];
switch (arg) {
case "b": return CreatureDifficulty.BOSS;
case "e": return CreatureDifficulty.ELITE;
default:
case "n": return CreatureDifficulty.NORMAL;
}
}
private int determineCombatLevel(String[] commandArgs) {
return Integer.parseInt(commandArgs[2]);
}
private void spawnNPC(Player player, String npcId, CreatureDifficulty difficulty, int combatLevel) {
CellObject cell = (CellObject) player.getCreatureObject().getParent();
SimpleSpawnInfo spawnInfo = SimpleSpawnInfo.builder()
.withNpcId(npcId)
.withDifficulty(difficulty)
.withMinLevel(combatLevel)
.withMaxLevel(combatLevel)
.withLocation(player.getCreatureObject().getLocation())
.withSpawnerFlag(NpcStaticSpawnLoader.SpawnerFlag.ATTACKABLE)
.withSpawnerType(SpawnerType.EGG)
.withBuildingId(determineBuildoutTag(cell))
.withCellId(determineCellId(cell))
.build();
CreateSpawnIntent.broadcast(spawnInfo);
}
private String determineBuildoutTag(CellObject cell) {
if (cell == null) {
return "";
}
SWGObject building = cell.getParent();
if (building == null) {
return "";
}
return building.getBuildoutTag();
}
private int determineCellId(CellObject cell) {
if (cell == null) {
return 0;
}
return cell.getNumber();
}
}

View File

@@ -0,0 +1,264 @@
/***********************************************************************************
* Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
* *
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
* Our goal is to create an emulator which will provide a server for players to *
* continue playing a game similar to the one they used to play. We are basing *
* it on the final publish of the game prior to end-game events. *
* *
* This file is part of Holocore. *
* *
* --------------------------------------------------------------------------------*
* *
* Holocore is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* Holocore is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
***********************************************************************************/
package com.projectswg.holocore.resources.support.npc.spawn;
import com.projectswg.common.data.location.Location;
import com.projectswg.common.data.location.Terrain;
import com.projectswg.holocore.resources.support.data.server_info.loader.npc.NpcStaticSpawnLoader;
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureDifficulty;
import com.projectswg.holocore.resources.support.objects.swg.custom.AIBehavior;
import java.util.concurrent.TimeUnit;
public class SimpleSpawnInfo implements SpawnInfo {
private String id;
private Terrain terrain;
private double x;
private double y;
private double z;
private int heading;
private int cellId;
private String spawnerType;
private String npcId;
private NpcStaticSpawnLoader.SpawnerFlag spawnerFlag;
private CreatureDifficulty difficulty;
private int minLevel;
private int maxLevel;
private String buildingId;
private String mood;
private AIBehavior behavior;
private String patrolId;
private NpcStaticSpawnLoader.PatrolFormation patrolFormation;
private int loiterRadius;
private int minSpawnTime;
private int maxSpawnTime;
private int amount;
private SimpleSpawnInfo() {
}
public static Builder builder() {
return new Builder();
}
@Override
public String getId() {
return id;
}
@Override
public Terrain getTerrain() {
return terrain;
}
@Override
public double getX() {
return x;
}
@Override
public double getY() {
return y;
}
@Override
public double getZ() {
return z;
}
@Override
public int getHeading() {
return heading;
}
@Override
public int getCellId() {
return cellId;
}
@Override
public String getSpawnerType() {
return spawnerType;
}
@Override
public String getNpcId() {
return npcId;
}
@Override
public NpcStaticSpawnLoader.SpawnerFlag getSpawnerFlag() {
return spawnerFlag;
}
@Override
public CreatureDifficulty getDifficulty() {
return difficulty;
}
@Override
public int getMinLevel() {
return minLevel;
}
@Override
public int getMaxLevel() {
return maxLevel;
}
@Override
public String getBuildingId() {
return buildingId;
}
@Override
public String getMood() {
return mood;
}
@Override
public AIBehavior getBehavior() {
return behavior;
}
@Override
public String getPatrolId() {
return patrolId;
}
@Override
public NpcStaticSpawnLoader.PatrolFormation getPatrolFormation() {
return patrolFormation;
}
@Override
public int getLoiterRadius() {
return loiterRadius;
}
@Override
public int getMinSpawnTime() {
return minSpawnTime;
}
@Override
public int getMaxSpawnTime() {
return maxSpawnTime;
}
@Override
public int getAmount() {
return amount;
}
public static class Builder {
private final SimpleSpawnInfo info;
private Builder() {
info = new SimpleSpawnInfo();
info.id = "simple";
info.behavior = AIBehavior.IDLE;
info.mood = "";
info.spawnerFlag = NpcStaticSpawnLoader.SpawnerFlag.INVULNERABLE;
info.buildingId = "";
info.amount = 1;
info.minSpawnTime = (int) TimeUnit.SECONDS.convert(8, TimeUnit.MINUTES);
info.maxSpawnTime = (int) TimeUnit.SECONDS.convert(12, TimeUnit.MINUTES);
}
public Builder withNpcId(String npcId) {
info.npcId = npcId;
info.patrolId = "";
return this;
}
public Builder withLocation(Location location) {
info.x = location.getX();
info.y = location.getY();
info.z = location.getZ();
info.terrain = location.getTerrain();
info.heading = (int) location.getYaw();
return this;
}
public Builder withBuildingId(String buildingId) {
info.buildingId = buildingId;
return this;
}
public Builder withCellId(int cellId) {
info.cellId = cellId;
return this;
}
public Builder withDifficulty(CreatureDifficulty difficulty) {
info.difficulty = difficulty;
return this;
}
public Builder withMinLevel(int minLevel) {
info.minLevel = minLevel;
return this;
}
public Builder withMaxLevel(int maxLevel) {
info.maxLevel = maxLevel;
return this;
}
public Builder withSpawnerFlag(NpcStaticSpawnLoader.SpawnerFlag spawnerFlag) {
info.spawnerFlag = spawnerFlag;
return this;
}
public Builder withSpawnerType(SpawnerType spawnerType) {
info.spawnerType = spawnerType.name();
return this;
}
public Builder withAmount(int amount) {
info.amount = amount;
return this;
}
public SimpleSpawnInfo build() {
return info;
}
}
}

View File

@@ -0,0 +1,79 @@
/***********************************************************************************
* Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
* *
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
* Our goal is to create an emulator which will provide a server for players to *
* continue playing a game similar to the one they used to play. We are basing *
* it on the final publish of the game prior to end-game events. *
* *
* This file is part of Holocore. *
* *
* --------------------------------------------------------------------------------*
* *
* Holocore is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* Holocore is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
***********************************************************************************/
package com.projectswg.holocore.resources.support.npc.spawn;
import com.projectswg.common.data.location.Terrain;
import com.projectswg.holocore.resources.support.data.server_info.loader.npc.NpcStaticSpawnLoader;
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureDifficulty;
import com.projectswg.holocore.resources.support.objects.swg.custom.AIBehavior;
public interface SpawnInfo {
String getId();
Terrain getTerrain();
double getX();
double getY();
double getZ();
int getHeading();
int getCellId();
String getSpawnerType();
String getNpcId();
NpcStaticSpawnLoader.SpawnerFlag getSpawnerFlag();
CreatureDifficulty getDifficulty();
int getMinLevel();
int getMaxLevel();
String getBuildingId();
String getMood();
AIBehavior getBehavior();
String getPatrolId();
NpcStaticSpawnLoader.PatrolFormation getPatrolFormation();
int getLoiterRadius();
int getMinSpawnTime();
int getMaxSpawnTime();
int getAmount();
}

View File

@@ -44,9 +44,9 @@ import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.ThreadLocalRandom
import java.util.stream.Collectors
class Spawner(spawn: StaticSpawnInfo, egg: SWGObject) {
class Spawner(spawn: SpawnInfo, egg: SWGObject) {
private val spawn: StaticSpawnInfo = Objects.requireNonNull(spawn, "spawn")
private val spawn: SpawnInfo = Objects.requireNonNull(spawn, "spawn")
private val npc: NpcInfo = Objects.requireNonNull(DataLoader.npcs().getNpc(spawn.npcId), "Invalid npc id: " + spawn.npcId)
private val npcsInternal = CopyOnWriteArrayList<AIObject>()

View File

@@ -112,6 +112,7 @@ public enum RadialHandler {
registerHandler(RareLootService.EXCEPTIONAL_CHEST, new RareLootRadial());
registerHandler(RareLootService.LEGENDARY_CHEST, new RareLootRadial());
registerHandler(GameObjectType.GOT_COMPONENT_SABER_CRYSTAL, new TuneCrystalRadial());
registerHandler("object/tangible/spawning/shared_spawn_egg.iff", new SpawnerRadial());
}
private void initializeContainerRadials() {

View File

@@ -0,0 +1,58 @@
/***********************************************************************************
* Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
* *
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
* Our goal is to create an emulator which will provide a server for players to *
* continue playing a game similar to the one they used to play. We are basing *
* it on the final publish of the game prior to end-game events. *
* *
* This file is part of Holocore. *
* *
* --------------------------------------------------------------------------------*
* *
* Holocore is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* Holocore is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
***********************************************************************************/
package com.projectswg.holocore.resources.support.objects.radial.object;
import com.projectswg.common.data.radial.RadialItem;
import com.projectswg.common.data.radial.RadialOption;
import com.projectswg.holocore.resources.support.global.player.AccessLevel;
import com.projectswg.holocore.resources.support.global.player.Player;
import com.projectswg.holocore.resources.support.objects.radial.RadialHandlerInterface;
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
import java.util.Collection;
public class SpawnerRadial implements RadialHandlerInterface {
@Override
public void getOptions(Collection<RadialOption> options, Player player, SWGObject target) {
if (isAllowedToDestroy(player)) {
options.add(RadialOption.create(RadialItem.ITEM_DESTROY));
}
}
@Override
public void handleSelection(Player player, SWGObject target, RadialItem selection) {
// The ITEM_DESTROY radial will cause the generic item destruction flow to be invoked
}
private boolean isAllowedToDestroy(Player player) {
AccessLevel accessLevel = player.getAccessLevel();
// Players have no access
return accessLevel != AccessLevel.PLAYER;
}
}

View File

@@ -99,6 +99,7 @@ public class CommandExecutionService extends Service {
registerCallback("dumpZoneInformation", CmdDumpZoneInformation::new);
registerCallback("goto", CmdGoto::new);
registerCallback("console_npc", CmdNpc::new);
registerCallback("createNPC", CmdCreateNpc::new);
registerCallback("qatool", CmdQaTool::new);
registerCallback("revertPlayerAppearance", CmdRevertPlayerAppearance::new);
registerCallback("setGodMode", CmdSetGodMode::new);

View File

@@ -31,16 +31,17 @@ import com.projectswg.common.data.location.Point3D
import com.projectswg.common.network.packets.swg.zone.CreateClientPathMessage
import com.projectswg.common.network.packets.swg.zone.DestroyClientPathMessage
import com.projectswg.common.network.packets.swg.zone.object_controller.IntendedTarget
import com.projectswg.holocore.intents.gameplay.world.spawn.CreateSpawnIntent
import com.projectswg.holocore.intents.support.global.network.InboundPacketIntent
import com.projectswg.holocore.intents.support.global.zone.PlayerEventIntent
import com.projectswg.holocore.intents.support.objects.swg.DestroyObjectIntent
import com.projectswg.holocore.intents.support.objects.swg.ObjectCreatedIntent
import com.projectswg.holocore.resources.support.data.server_info.StandardLog
import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader
import com.projectswg.holocore.resources.support.data.server_info.loader.npc.NpcStaticSpawnLoader.StaticSpawnInfo
import com.projectswg.holocore.resources.support.data.server_info.mongodb.PswgDatabase
import com.projectswg.holocore.resources.support.global.player.PlayerEvent
import com.projectswg.holocore.resources.support.npc.spawn.NPCCreator
import com.projectswg.holocore.resources.support.npc.spawn.SpawnInfo
import com.projectswg.holocore.resources.support.npc.spawn.Spawner
import com.projectswg.holocore.resources.support.npc.spawn.SpawnerType
import com.projectswg.holocore.resources.support.objects.ObjectCreator
@@ -112,20 +113,57 @@ class SpawnerService : Service() {
@IntentHandler
private fun handleDestroyObjectIntent(doi: DestroyObjectIntent) {
val destroyedObject = doi.getObject() as? AIObject ?: return
val obj = doi.`object`
if (isNPC(obj)) {
handleNPCDestroyed(obj)
}
if (isSpawner(obj)) {
handleSpawnerDestroyed(obj)
}
}
@IntentHandler
private fun handleCreateSpawnIntent(csi: CreateSpawnIntent) {
spawn(csi.spawnInfo)
}
private fun isNPC(obj: SWGObject): Boolean {
return obj is AIObject
}
private fun isSpawner(obj: SWGObject): Boolean {
return obj.getServerAttribute(ServerAttribute.EGG_SPAWNER) != null
}
private fun handleNPCDestroyed(obj: SWGObject) {
val destroyedObject = obj as? AIObject ?: return
val spawner = destroyedObject.spawner
if (spawner == null) {
Log.e("Killed AI object %s has no linked Spawner - it cannot respawn!", destroyedObject)
Log.i("Killed AI object %s has no linked Spawner - it will not respawn", destroyedObject)
return
}
spawner.removeNPC(destroyedObject)
if (spawner.behavior != AIBehavior.PATROL || spawner.npcs.isEmpty())
executor.execute((spawner.respawnDelay * 1000).toLong()) { respawn(spawner) }
}
private fun handleSpawnerDestroyed(obj: SWGObject) {
val spawner = obj.getServerAttribute(ServerAttribute.EGG_SPAWNER) as Spawner
val npcs = spawner.npcs.toList()
for (npc in npcs) {
npc.spawner = null // Prevents the NPC from respawning
DestroyObjectIntent.broadcast(npc)
}
}
private fun loadSpawners() {
val startTime = StandardLog.onStartLoad("spawners")
@@ -143,7 +181,7 @@ class SpawnerService : Service() {
StandardLog.onEndLoad(count, "spawners", startTime)
}
private fun spawn(spawn: StaticSpawnInfo) {
private fun spawn(spawn: SpawnInfo) {
val egg = createEgg(spawn)
val spawner = Spawner(spawn, egg)
egg.setServerAttribute(ServerAttribute.EGG_SPAWNER, spawner)
@@ -172,7 +210,7 @@ class SpawnerService : Service() {
}
}
private fun createEgg(spawn: StaticSpawnInfo): SWGObject {
private fun createEgg(spawn: SpawnInfo): SWGObject {
val spawnerType = SpawnerType.valueOf(spawn.spawnerType)
val egg = ObjectCreator.createObjectFromTemplate(spawnerType.objectTemplate)
egg.containerPermissions = AdminPermissions.getPermissions()