mirror of
https://github.com/ProjectSWGCore/Holocore.git
synced 2026-09-11 21:45:26 -04:00
Merge pull request #674 from madsboddum/Holocore-671
Holocore-671 Previous learned and dropped ability can still be execut…
This commit is contained in:
+5
-5
@@ -47,7 +47,6 @@ import com.projectswg.holocore.resources.support.objects.swg.player.PlayerObject
|
||||
import com.projectswg.holocore.resources.support.objects.swg.tangible.TangibleObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.weapon.DefaultWeaponFactory;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.weapon.WeaponObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.weapon.WeaponType;
|
||||
import com.projectswg.holocore.services.support.objects.ObjectStorageService.BuildingLookup;
|
||||
import me.joshlarson.jlcommon.utilities.Arguments;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -61,12 +60,10 @@ public class CharacterCreation {
|
||||
|
||||
private final Player player;
|
||||
private final ClientCreateCharacter create;
|
||||
private final String biography;
|
||||
|
||||
public CharacterCreation(Player player, ClientCreateCharacter create, String biography) {
|
||||
public CharacterCreation(Player player, ClientCreateCharacter create) {
|
||||
this.player = player;
|
||||
this.create = create;
|
||||
this.biography = biography;
|
||||
}
|
||||
|
||||
public CreatureObject createCharacter(AccessLevel accessLevel, ZoneInsertion info) {
|
||||
@@ -79,7 +76,7 @@ public class CharacterCreation {
|
||||
createHair(creatureObj, create.getHair(), create.getHairCustomization());
|
||||
createStarterClothing(creatureObj, race, create.getClothes());
|
||||
playerObj.setAdminTag(accessLevel);
|
||||
playerObj.setBiography(biography);
|
||||
playerObj.setBiography(create.getBiography());
|
||||
|
||||
ObjectCreatedIntent.broadcast(playerObj);
|
||||
ObjectCreatedIntent.broadcast(creatureObj);
|
||||
@@ -165,6 +162,9 @@ public class CharacterCreation {
|
||||
// new GrantSkillIntent(GrantSkillIntent.IntentType.GRANT, "crafting_artisan_novice", creatureObj, true).broadcast();
|
||||
new GrantSkillIntent(GrantSkillIntent.IntentType.GRANT, "combat_brawler_novice", creatureObj, true).broadcast();
|
||||
// new GrantSkillIntent(GrantSkillIntent.IntentType.GRANT, "combat_marksman_novice", creatureObj, true).broadcast();
|
||||
|
||||
// Everyone can Burst Run
|
||||
creatureObj.addCommand("burstrun");
|
||||
|
||||
Collection<String> languages = languagesSkillsForRace(creatureObj.getRace());
|
||||
|
||||
|
||||
+17
-1
@@ -38,23 +38,30 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CommandQueueService extends Service {
|
||||
|
||||
private final ScheduledThreadPool executor;
|
||||
private final Map<CreatureObject, CreatureCombatQueue> combatQueueMap;
|
||||
private final CombatCommandHandler combatCommandHandler;
|
||||
private final long delayBetweenCheckingCommandQueue;
|
||||
|
||||
public CommandQueueService() {
|
||||
this(100);
|
||||
}
|
||||
|
||||
public CommandQueueService(long delayBetweenCheckingCommandQueue) {
|
||||
this.executor = new ScheduledThreadPool(4, "command-queue-%d");
|
||||
this.combatQueueMap = new ConcurrentHashMap<>();
|
||||
this.combatCommandHandler = new CombatCommandHandler();
|
||||
this.delayBetweenCheckingCommandQueue = delayBetweenCheckingCommandQueue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean initialize() {
|
||||
executor.start();
|
||||
executor.executeWithFixedRate(0, 100, this::executeQueuedCommands);
|
||||
executor.executeWithFixedRate(0, delayBetweenCheckingCommandQueue, this::executeQueuedCommands);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -331,6 +338,15 @@ public class CommandQueueService extends Service {
|
||||
}
|
||||
|
||||
if (rootCommand instanceof CombatCommand combatCommand) {
|
||||
Collection<String> sourceCommands = source.getCommands()
|
||||
.stream()
|
||||
.map(sourceCommand -> sourceCommand.toLowerCase(Locale.US))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (!sourceCommands.contains(rootCommand.getName())) {
|
||||
return new CheckCommandResult(ErrorCode.ABILITY, 0);
|
||||
}
|
||||
|
||||
if (combatCommand.getHitType() == HitType.HEAL && combatCommand.getAttackType() == AttackType.SINGLE_TARGET) {
|
||||
SWGObject target;
|
||||
switch (combatCommand.getTargetType()) {
|
||||
|
||||
+12
-18
@@ -169,23 +169,17 @@ public class CharacterCreationService extends Service {
|
||||
}
|
||||
|
||||
private void sendCharCreationFailure(Player player, ClientCreateCharacter create, ErrorMessage err, String actualReason) {
|
||||
NameFailureReason reason = NameFailureReason.NAME_SYNTAX;
|
||||
switch (err) {
|
||||
case NAME_DECLINED_INTERNAL_ERROR:
|
||||
case NAME_APPROVED:
|
||||
reason = NameFailureReason.NAME_RETRY;
|
||||
break;
|
||||
case NAME_DECLINED_FICTIONALLY_INAPPROPRIATE:
|
||||
reason = NameFailureReason.NAME_FICTIONALLY_INAPPRORIATE;
|
||||
break;
|
||||
case NAME_DECLINED_IN_USE: reason = NameFailureReason.NAME_IN_USE; break;
|
||||
case NAME_DECLINED_EMPTY: reason = NameFailureReason.NAME_DECLINED_EMPTY; break;
|
||||
case NAME_DECLINED_RESERVED: reason = NameFailureReason.NAME_DEV_RESERVED; break;
|
||||
case NAME_DECLINED_TOO_FAST: reason = NameFailureReason.NAME_TOO_FAST; break;
|
||||
case SERVER_CHARACTER_CREATION_MAX_CHARS: reason = NameFailureReason.TOO_MANY_CHARACTERS; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
NameFailureReason reason = switch (err) {
|
||||
case NAME_DECLINED_INTERNAL_ERROR, NAME_APPROVED -> NameFailureReason.NAME_RETRY;
|
||||
case NAME_DECLINED_FICTIONALLY_INAPPROPRIATE -> NameFailureReason.NAME_FICTIONALLY_INAPPRORIATE;
|
||||
case NAME_DECLINED_IN_USE -> NameFailureReason.NAME_IN_USE;
|
||||
case NAME_DECLINED_EMPTY -> NameFailureReason.NAME_DECLINED_EMPTY;
|
||||
case NAME_DECLINED_RESERVED -> NameFailureReason.NAME_DEV_RESERVED;
|
||||
case NAME_DECLINED_TOO_FAST -> NameFailureReason.NAME_TOO_FAST;
|
||||
case SERVER_CHARACTER_CREATION_MAX_CHARS -> NameFailureReason.TOO_MANY_CHARACTERS;
|
||||
default -> NameFailureReason.NAME_SYNTAX;
|
||||
};
|
||||
|
||||
StandardLog.onPlayerError(this, player, "failed to create character '%s' with server error [%s] from %s", create.getName(), actualReason, create.getSocketAddress());
|
||||
player.sendPacket(new CreateCharacterFailure(reason));
|
||||
}
|
||||
@@ -225,7 +219,7 @@ public class CharacterCreationService extends Service {
|
||||
Log.e("Failed to get spawn information for location: " + spawnLocation);
|
||||
return null;
|
||||
}
|
||||
CharacterCreation creation = new CharacterCreation(player, create, create.getBiography());
|
||||
CharacterCreation creation = new CharacterCreation(player, create);
|
||||
return creation.createCharacter(player.getAccessLevel(), info);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ class EquipArmorTest : TestRunnerSimulatedWorld() {
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
registerService(CommandQueueService())
|
||||
registerService(CommandQueueService(5))
|
||||
registerService(CommandExecutionService())
|
||||
registerService(SkillService())
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ class EquipClothingTest : TestRunnerSimulatedWorld() {
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
registerService(CommandQueueService())
|
||||
registerService(CommandQueueService(5))
|
||||
registerService(CommandExecutionService())
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ class EquipLightsaberTest : TestRunnerSimulatedWorld() {
|
||||
|
||||
@BeforeEach
|
||||
internal fun setUp() {
|
||||
registerService(CommandQueueService())
|
||||
registerService(CommandQueueService(5))
|
||||
registerService(CommandExecutionService())
|
||||
registerService(SkillService())
|
||||
registerService(LightsaberService())
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ class EquipWeaponTest : TestRunnerSimulatedWorld() {
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
registerService(CommandQueueService())
|
||||
registerService(CommandQueueService(5))
|
||||
registerService(CommandExecutionService())
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ class LightsaberInventoryTest : TestRunnerSimulatedWorld() {
|
||||
|
||||
@BeforeEach
|
||||
internal fun setUp() {
|
||||
registerService(CommandQueueService())
|
||||
registerService(CommandQueueService(5))
|
||||
registerService(CommandExecutionService())
|
||||
registerService(SkillService())
|
||||
registerService(LightsaberService())
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.projectswg.holocore.services.gameplay.combat
|
||||
|
||||
import com.projectswg.common.data.CRC
|
||||
import com.projectswg.common.network.packets.swg.zone.object_controller.CommandQueueEnqueue
|
||||
import com.projectswg.common.network.packets.swg.zone.object_controller.CommandTimer
|
||||
import com.projectswg.holocore.intents.gameplay.player.experience.skills.GrantSkillIntent
|
||||
import com.projectswg.holocore.intents.support.global.network.InboundPacketIntent
|
||||
import com.projectswg.holocore.intents.support.global.network.OutboundPacketIntent
|
||||
import com.projectswg.holocore.intents.support.objects.swg.ObjectCreatedIntent
|
||||
import com.projectswg.holocore.resources.support.objects.ObjectCreator
|
||||
import com.projectswg.holocore.resources.support.objects.swg.weapon.DefaultWeaponFactory
|
||||
import com.projectswg.holocore.services.gameplay.player.experience.skills.SkillService
|
||||
import com.projectswg.holocore.services.support.global.commands.CommandExecutionService
|
||||
import com.projectswg.holocore.services.support.global.commands.CommandQueueService
|
||||
import com.projectswg.holocore.test.resources.GenericCreatureObject
|
||||
import com.projectswg.holocore.test.resources.GenericPlayer
|
||||
import com.projectswg.holocore.test.runners.TestRunnerSimulatedWorld
|
||||
import org.junit.jupiter.api.Assertions.*
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class AbilityTest : TestRunnerSimulatedWorld() {
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
registerService(CommandQueueService(5))
|
||||
registerService(CommandExecutionService())
|
||||
registerService(SkillService())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `you can execute an ability when you have the skill that grants it`() {
|
||||
val creatureObject = createCreatureObject()
|
||||
val player = creatureObject.owner ?: throw RuntimeException("Unable to access player")
|
||||
grantRequiredSkillForParryRiposte(creatureObject)
|
||||
|
||||
val success = parryRiposte(player)
|
||||
|
||||
assertTrue(success)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `you cannot execute an ability when you are missing the skill that grants it`() {
|
||||
val creatureObject = createCreatureObject()
|
||||
val player = creatureObject.owner ?: throw RuntimeException("Unable to access player")
|
||||
|
||||
val success = parryRiposte(player)
|
||||
|
||||
assertFalse(success)
|
||||
}
|
||||
|
||||
private fun grantRequiredSkillForParryRiposte(creatureObject: GenericCreatureObject) {
|
||||
GrantSkillIntent.broadcast(GrantSkillIntent.IntentType.GRANT, "combat_brawler_master", creatureObject, true)
|
||||
waitForIntents()
|
||||
}
|
||||
|
||||
private fun parryRiposte(player: GenericPlayer): Boolean {
|
||||
val crc = CRC.getCrc("parryriposte")
|
||||
InboundPacketIntent.broadcast(player, CommandQueueEnqueue(player.creatureObject.objectId, 0, crc, 0, ""))
|
||||
|
||||
val commandTimer = player.waitForNextPacket(CommandTimer::class.java)
|
||||
|
||||
if (commandTimer != null) {
|
||||
return commandTimer.flags.contains(CommandTimer.CommandTimerFlag.EXECUTE)
|
||||
} else {
|
||||
throw RuntimeException("No CommandTimer packet was sent at all")
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCreatureObject(): GenericCreatureObject {
|
||||
val creatureObject = GenericCreatureObject(ObjectCreator.getNextObjectId())
|
||||
ObjectCreatedIntent.broadcast(creatureObject)
|
||||
val defaultWeapon = DefaultWeaponFactory.createDefaultWeapon()
|
||||
defaultWeapon.moveToContainer(creatureObject)
|
||||
creatureObject.equippedWeapon = defaultWeapon
|
||||
return creatureObject
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,17 @@
|
||||
package com.projectswg.holocore.services.gameplay.combat
|
||||
|
||||
import com.projectswg.common.data.CRC
|
||||
import com.projectswg.common.network.packets.swg.login.creation.ClientCreateCharacter
|
||||
import com.projectswg.common.network.packets.swg.zone.object_controller.CommandQueueEnqueue
|
||||
import com.projectswg.holocore.intents.support.global.network.InboundPacketIntent
|
||||
import com.projectswg.holocore.intents.support.objects.swg.ObjectCreatedIntent
|
||||
import com.projectswg.holocore.resources.support.objects.ObjectCreator
|
||||
import com.projectswg.holocore.resources.support.objects.swg.weapon.DefaultWeaponFactory
|
||||
import com.projectswg.holocore.services.gameplay.combat.buffs.BuffService
|
||||
import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader
|
||||
import com.projectswg.holocore.resources.support.global.player.AccessLevel
|
||||
import com.projectswg.holocore.resources.support.global.player.Player
|
||||
import com.projectswg.holocore.resources.support.global.zone.creation.CharacterCreation
|
||||
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject
|
||||
import com.projectswg.holocore.services.support.global.commands.CommandExecutionService
|
||||
import com.projectswg.holocore.services.support.global.commands.CommandQueueService
|
||||
import com.projectswg.holocore.test.resources.GenericCreatureObject
|
||||
import com.projectswg.holocore.test.resources.GenericPlayer
|
||||
import com.projectswg.holocore.test.runners.TestRunnerSimulatedWorld
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
@@ -22,7 +24,7 @@ class AttackCostTest : TestRunnerSimulatedWorld() {
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
registerService(BuffService())
|
||||
registerService(CommandQueueService())
|
||||
registerService(CommandQueueService(5))
|
||||
registerService(CommandExecutionService())
|
||||
registerService(CombatStatusService())
|
||||
}
|
||||
@@ -90,19 +92,26 @@ class AttackCostTest : TestRunnerSimulatedWorld() {
|
||||
assertFalse(creatureObject.hasBuff("burstRun"))
|
||||
}
|
||||
|
||||
private fun burstRun(player: GenericPlayer) {
|
||||
private fun burstRun(player: Player) {
|
||||
val crc = CRC.getCrc("burstrun")
|
||||
|
||||
broadcastAndWait(InboundPacketIntent(player, CommandQueueEnqueue(player.creatureObject.objectId, 0, crc, 0, "")))
|
||||
Thread.sleep(150) // Give the command queue a chance to be processed
|
||||
Thread.sleep(10) // Give the command queue a chance to be processed
|
||||
}
|
||||
|
||||
private fun createCreatureObject(): GenericCreatureObject {
|
||||
val creatureObject = GenericCreatureObject(ObjectCreator.getNextObjectId())
|
||||
ObjectCreatedIntent.broadcast(creatureObject)
|
||||
val defaultWeapon = DefaultWeaponFactory.createDefaultWeapon()
|
||||
defaultWeapon.moveToContainer(creatureObject)
|
||||
creatureObject.equippedWeapon = defaultWeapon
|
||||
private fun createCreatureObject(): CreatureObject {
|
||||
val player = GenericPlayer()
|
||||
val clientCreateCharacter = ClientCreateCharacter()
|
||||
clientCreateCharacter.biography = ""
|
||||
clientCreateCharacter.clothes = "combat_brawler"
|
||||
clientCreateCharacter.race = "object/creature/player/shared_human_male.iff"
|
||||
clientCreateCharacter.name = "Testing Character"
|
||||
val characterCreation = CharacterCreation(player, clientCreateCharacter)
|
||||
|
||||
val mosEisley = DataLoader.zoneInsertions().getInsertion("tat_moseisley")
|
||||
val creatureObject = characterCreation.createCharacter(AccessLevel.PLAYER, mosEisley)
|
||||
creatureObject.owner = player
|
||||
|
||||
return creatureObject
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.projectswg.common.data.CRC
|
||||
import com.projectswg.common.data.encodables.tangible.PvpStatus
|
||||
import com.projectswg.common.network.packets.swg.zone.object_controller.CommandQueueEnqueue
|
||||
import com.projectswg.holocore.intents.gameplay.gcw.faction.FactionIntent
|
||||
import com.projectswg.holocore.intents.gameplay.player.experience.skills.GrantSkillIntent
|
||||
import com.projectswg.holocore.intents.support.global.network.InboundPacketIntent
|
||||
import com.projectswg.holocore.intents.support.objects.swg.ObjectCreatedIntent
|
||||
import com.projectswg.holocore.resources.support.data.server_info.loader.ServerData
|
||||
@@ -12,6 +13,7 @@ import com.projectswg.holocore.resources.support.objects.ObjectCreator
|
||||
import com.projectswg.holocore.resources.support.objects.swg.SWGObject
|
||||
import com.projectswg.holocore.resources.support.objects.swg.weapon.DefaultWeaponFactory
|
||||
import com.projectswg.holocore.services.gameplay.faction.FactionFlagService
|
||||
import com.projectswg.holocore.services.gameplay.player.experience.skills.SkillService
|
||||
import com.projectswg.holocore.services.support.global.commands.CommandExecutionService
|
||||
import com.projectswg.holocore.services.support.global.commands.CommandQueueService
|
||||
import com.projectswg.holocore.test.resources.GenericCreatureObject
|
||||
@@ -25,7 +27,8 @@ class FactionPvpTest : TestRunnerSimulatedWorld() {
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
registerService(CommandQueueService())
|
||||
registerService(SkillService())
|
||||
registerService(CommandQueueService(5))
|
||||
registerService(CommandExecutionService())
|
||||
registerService(FactionFlagService())
|
||||
registerService(CombatStatusService())
|
||||
@@ -66,11 +69,12 @@ class FactionPvpTest : TestRunnerSimulatedWorld() {
|
||||
val targetObjectId = target.objectId
|
||||
|
||||
broadcastAndWait(InboundPacketIntent(player, CommandQueueEnqueue(player.creatureObject.objectId, 0, crc, targetObjectId, "")))
|
||||
Thread.sleep(150) // Give the command queue a chance to be processed
|
||||
Thread.sleep(10) // Give the command queue a chance to be processed
|
||||
}
|
||||
|
||||
private fun createCreatureObject(): GenericCreatureObject {
|
||||
val creatureObject = GenericCreatureObject(ObjectCreator.getNextObjectId())
|
||||
GrantSkillIntent.broadcast(GrantSkillIntent.IntentType.GRANT, "species_human", creatureObject, true)
|
||||
ObjectCreatedIntent.broadcast(creatureObject)
|
||||
val defaultWeapon = DefaultWeaponFactory.createDefaultWeapon()
|
||||
defaultWeapon.moveToContainer(creatureObject)
|
||||
|
||||
Reference in New Issue
Block a user