Restructure repository

* Move /common/src to /src
* Move services to net.psforever package
* Move /pslogin to /server
This commit is contained in:
Jakob Gillich 2020-08-23 03:26:06 +02:00
parent 89a30ae6f6
commit f4fd78fc5d
958 changed files with 527 additions and 725 deletions

View file

@ -0,0 +1,69 @@
CREATE TABLE IF NOT EXISTS "accounts" (
"id" SERIAL PRIMARY KEY NOT NULL,
"username" VARCHAR(64) NOT NULL UNIQUE,
"passhash" VARCHAR(64) NOT NULL,
"created" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"last_modified" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"inactive" BOOLEAN NOT NULL DEFAULT FALSE,
"gm" BOOLEAN NOT NULL DEFAULT FALSE
);
CREATE TABLE IF NOT EXISTS "characters" (
"id" SERIAL PRIMARY KEY NOT NULL,
"name" VARCHAR(64) NOT NULL,
"account_id" INT NOT NULL REFERENCES accounts (id),
"faction_id" INT NOT NULL,
"gender_id" INT NOT NULL,
"head_id" INT NOT NULL,
"voice_id" INT NOT NULL,
"created" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"last_login" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"last_modified" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" BOOLEAN NOT NULL DEFAULT FALSE
);
CREATE TABLE IF NOT EXISTS "logins" (
"id" SERIAL PRIMARY KEY NOT NULL,
"account_id" INT NOT NULL REFERENCES accounts (id),
"login_time" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"ip_address" VARCHAR(32) NOT NULL,
"canonical_hostname" VARCHAR(132) NOT NULL,
"hostname" VARCHAR(132) NOT NULL,
"port" INT NOT NULL
);
CREATE TABLE IF NOT EXISTS "loadouts" (
"id" SERIAL PRIMARY KEY NOT NULL,
"characters_id" INT NOT NULL REFERENCES characters (id),
"loadout_number" INT NOT NULL,
"exosuit_id" INT NOT NULL,
"name" VARCHAR(36) NOT NULL,
"items" TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS "lockers" (
"id" SERIAL PRIMARY KEY NOT NULL,
"characters_id" INT NOT NULL REFERENCES characters (id),
"items" TEXT NOT NULL
);
--These triggers update the last_modified timestamp column when a table is updated
CREATE OR REPLACE FUNCTION fn_set_last_modified_timestamp()
RETURNS TRIGGER AS $$
BEGIN
NEW.last_modified = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trigger_accounts_set_last_modified on accounts;
CREATE TRIGGER trigger_accounts_set_last_modified
BEFORE UPDATE ON accounts
FOR EACH ROW
EXECUTE PROCEDURE fn_set_last_modified_timestamp();
DROP TRIGGER IF EXISTS trigger_players_set_last_modified on characters;
CREATE TRIGGER trigger_players_set_last_modified
BEFORE UPDATE ON characters
FOR EACH ROW
EXECUTE PROCEDURE fn_set_last_modified_timestamp();

View file

@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS "buildings" (
local_id INT NOT NULL,
zone_id INT NOT NULL,
faction_id INT NOT NULL,
PRIMARY KEY (local_id, zone_id)
);

View file

@ -0,0 +1,29 @@
ALTER TABLE characters RENAME TO avatar;
ALTER TABLE avatar RENAME CONSTRAINT characters_account_id_fkey TO avatar_account_id_fkey;
ALTER TABLE accounts RENAME TO account;
ALTER TABLE logins RENAME TO login;
ALTER TABLE login RENAME CONSTRAINT logins_account_id_fkey TO login_account_id_fkey;
ALTER TABLE loadouts RENAME TO loadout;
ALTER TABLE loadout RENAME COLUMN characters_id TO avatar_id;
ALTER TABLE loadout RENAME CONSTRAINT loadouts_characters_id_fkey TO loadout_avatar_id_fkey;
ALTER TABLE lockers RENAME TO locker;
ALTER TABLE locker RENAME COLUMN characters_id TO avatar_id;
ALTER TABLE locker RENAME CONSTRAINT lockers_characters_id_fkey TO locker_avatar_id_fkey;
ALTER TABLE buildings RENAME TO building;
ALTER TABLE avatar
ADD COLUMN bep BIGINT NOT NULL DEFAULT 0,
ADD COLUMN cep BIGINT NOT NULL DEFAULT 0,
ADD COLUMN cosmetics INT;
CREATE TABLE certification (
id INT NOT NULL,
avatar_id INT NOT NULL REFERENCES avatar (id),
PRIMARY KEY (id, avatar_id)
);
CREATE TABLE implant (
name TEXT NOT NULL,
avatar_id INT NOT NULL REFERENCES avatar (id),
PRIMARY KEY (name, avatar_id)
);

View file

@ -0,0 +1,102 @@
add_property ace allowed false
add_property ace equiptime 500
add_property ace holstertime 500
add_property ace_deployable allowed false
add_property ace_deployable equiptime 500
add_property ace_deployable holstertime 500
add_property advanced_ace equiptime 750
add_property advanced_ace holstertime 750
add_property ams maxhealth 5000
add_property ams jacking_duration 0 60 40 30
add_property anniversary_gun equiptime 500
add_property anniversary_gun holstertime 500
add_property anniversary_guna equiptime 500
add_property anniversary_guna holstertime 500
add_property anniversary_gunb equiptime 500
add_property anniversary_gunb holstertime 500
add_property aphelion_flight requirement_award0 false
add_property applicator equiptime 500
add_property applicator firemode0_refiretime 500
add_property applicator firemode1_refiretime 500
add_property applicator holstertime 500
add_property bank equiptime 500
add_property bank holstertime 500
add_property beamer equiptime 500
add_property beamer holstertime 500
add_property boomer_trigger equiptime 500
add_property chainblade equiptime 250
add_property chainblade holstertime 250
add_property colossus_flight requirement_award0 false
add_property command_detonater allowed false
add_property command_detonater equiptime 500
add_property command_detonater holstertime 500
add_property cycler equiptime 600
add_property cycler holstertime 600
add_property cycler_v2 equiptime 600
add_property cycler_v2 holstertime 600
add_property cycler_v3 equiptime 600
add_property cycler_v3 holstertime 600
add_property cycler_v4 equiptime 600
add_property cycler_v4 holstertime 600
add_property flail_targeting_laser equiptime 500
add_property flail_targeting_laser holstertime 500
add_property flamethrower equiptime 1000
add_property flamethrower holstertime 1000
add_property flechette equiptime 600
add_property flechette holstertime 600
add_property forceblade equiptime 250
add_property forceblade holstertime 250
add_property galaxy_gunship allowed false
add_property galaxy_gunship maxhealth 9500
add_property gauss equiptime 600
add_property gauss holstertime 600
add_property ilc9 equiptime 500
add_property ilc9 holstertime 500
add_property isp equiptime 500
add_property isp holstertime 500
add_property katana equiptime 250
add_property katana holstertime 250
add_property lasher equiptime 750
add_property lasher holstertime 750
add_property lasher_projectile lash_delay 0.00
add_property lasher_projectile_ap lash_delay 0.00
add_property lasher_projectile_ap lasher_projectile_ap false
add_property lasher_projectile_ap lasher_projectile true
add_property maelstrom equiptime 1000
add_property maelstrom holstertime 1000
add_property magcutter equiptime 250
add_property magcutter holstertime 250
add_property medicalapplicator equiptime 500
add_property medicalapplicator holstertime 500
add_property medicalapplicator firemode0_refiretime 500
add_property medicalapplicator firemode1_refiretime 500
add_property mini_chaingun equiptime 750
add_property mini_chaingun holstertime 750
add_property nano_dispenser equiptime 750
add_property nano_dispenser holstertime 750
add_property pellet_gun equiptime 600
add_property pellet_gun holstertime 600
add_property peregrine_flight requirement_award0 false
add_property pulsar equiptime 600
add_property pulsar holstertime 600
add_property punisher equiptime 600
add_property punisher holstertime 600
add_property r_shotgun equiptime 750
add_property r_shotgun holstertime 750
add_property remote_electronics_kit equiptime 500
add_property remote_electronics_kit holstertime 500
add_property repeater equiptime 500
add_property repeater holstertime 500
add_property six_shooter equiptime 500
add_property six_shooter holstertime 500
add_property spiker equiptime 500
add_property spiker holstertime 500
add_property super_staminakit allowed true
add_property super_staminakit medkit_reuse_delay 300
add_property super_staminakit nodrop false
add_property super_staminakit requirement_award0 false
add_property suppressor equiptime 600
add_property suppressor holstertime 600
add_property trek equiptime 500
add_property trek holstertime 500
add_property vulture requirement_award0 false

View file

@ -0,0 +1,54 @@
add_property ams requirement_certification0 false
add_property apc requirement_certification0 false
add_property aphelion allowed false
add_property aphelion_flight allowed false
add_property aphelion_gunner allowed false
add_property aurora requirement_certification0 false
add_property battlewagon requirement_certification0 false
add_property colossus allowed false
add_property colossus_flight allowed false
add_property colossus_gunner allowed false
add_property delivererv requirement_certification0 false
add_property dropship allowed false
add_property flail requirement_certification0 false
add_property fury requirement_certification0 false
add_property galaxy_gunship allowed false
add_property liberator allowed false
add_property lightgunship allowed false
add_property lightning requirement_certification0 false
add_property lodestar allowed false
add_property magrider purchase_tech_plant false
add_property magrider requirement_certification0 false
add_property mediumtransport requirement_certification0 false
add_property mosquito allowed false
add_property nano_dispenser requirement_certification0 false
add_property nchev_antiaircraft allowed false
add_property order_terminal forsale_nchev_antiaircraft false
add_property order_terminal forsale_trhev_antiaircraft false
add_property order_terminal forsale_vshev_antiaircraft false
add_property peregrine allowed false
add_property peregrine_flight allowed false
add_property peregrine_gunner allowed false
add_property phantasm allowed false
add_property prowler purchase_tech_plant false
add_property prowler requirement_certification0 false
add_property quadassault requirement_certification0 false
add_property quadstealth requirement_certification0 false
add_property skyguard requirement_certification0 false
add_property skyguard requirement_certification1 false
add_property threemanheavybuggy requirement_certification0 false
add_property threemanheavybuggy requirement_certification1 false
add_property thunderer requirement_certification0 false
add_property trhev_antiaircraft allowed false
add_property two_man_assault_buggy requirement_certification0 false
add_property two_man_assault_buggy requirement_certification1 false
add_property two_man_assault_buggy requirement_certification2 false
add_property twomanheavybuggy requirement_certification0 false
add_property twomanheavybuggy requirement_certification1 false
add_property twomanhoverbuggy requirement_certification0 false
add_property twomanhoverbuggy requirement_certification1 false
add_property vanguard purchase_tech_plant false
add_property vanguard requirement_certification0 false
add_property vshev_antiaircraft allowed false
add_property vulture allowed false
add_property wasp allowed false

View file

@ -0,0 +1,61 @@
add_property air_vehicle_terminal forsale_dropship
add_property air_vehicle_terminal forsale_galaxy_gunship
add_property air_vehicle_terminal forsale_lodestar
add_property apc allowed false
add_property apc_nc allowed false
add_property apc_tr allowed false
add_property apc_vs allowed false
add_property aphelion allowed false
add_property aphelion_flight allowed false
add_property aurora allowed false
add_property battlewagon allowed false
add_property colossus_flight allowed false
add_property colossus_gunner allowed false
add_property dropship requirement_certification0 false
add_property flail allowed false
add_property fury allowed false
add_property galaxy_gunship requirement_certification0 false
add_property hunterseeker requirement_certification0 false
add_property lancer requirement_certification0 false
add_property liberator requirement_certification0 false
add_property liberator purchase_tech_plant false
add_property lightgunship requirement_certification0 false
add_property lightgunship purchase_tech_plant false
add_property lightning allowed false
add_property lodestar requirement_certification0 false
add_property magrider allowed false
add_property mediumtransport allowed false
add_property mosquito requirement_certification0 false
add_property mosquito requirement_certification1 false
add_property nano_dispenser requirement_certification0 false
add_property nchev_antiaircraft allowed false
add_property order_terminal forsale_nchev_antiaircraft false
add_property order_terminal forsale_trhev_antiaircraft false
add_property order_terminal forsale_vshev_antiaircraft false
add_property peregrine_flight allowed false
add_property peregrine_gunner allowed false
add_property phantasm requirement_certification0 false
add_property phoenix requirement_certification0 false
add_property prowler allowed false
add_property quadassault allowed false
add_property quadstealth allowed false
add_property skyguard allowed false
add_property striker requirement_certification0 false
add_property switchblade allowed false
add_property threemanheavybuggy allowed false
add_property thunderer allowed false
add_property trhev_antiaircraft allowed false
add_property two_man_assault_buggy allowed false
add_property twomanheavybuggy allowed false
add_property twomanhoverbuggy allowed false
add_property vanguard allowed false
add_property vehicle_terminal_combined forsale_dropship
add_property vehicle_terminal_combined forsale_galaxy_gunship
add_property vehicle_terminal_combined forsale_lodestar
add_property vshev_antiaircraft allowed false
add_property vulture requirement_award0 false
add_property vulture requirement_certification0 false
add_property vulture purchase_tech_plant false
add_property wasp purchase_tech_plant false
add_property wasp requirement_certification0 false
add_property wasp requirement_certification1 false

View file

@ -0,0 +1,134 @@
add_property ace requirement_certification0 false # combat_engineering
add_property ace_deployable requirement_certification0 false # combat_engineering
add_property advanced_ace firemode0_requirement_certification0 false # ce_defense
add_property advanced_ace firemode0_requirement_certification1 false # ce_advanced
add_property advanced_ace firemode1_requirement_certification0 false # ce_offense
add_property advanced_ace firemode1_requirement_certification1 false # ce_advanced
add_property advanced_ace firemode2_requirement_certification0 false # ce_offense
add_property advanced_ace firemode2_requirement_certification1 false # ce_advanced
add_property advanced_ace requirement_certification0 false # ce_defense
add_property advanced_ace requirement_certification1 false # ce_offense
add_property advanced_ace requirement_certification2 false # ce_advanced
add_property air_vehicle_terminal forsale_dropship
add_property air_vehicle_terminal forsale_galaxy_gunship
add_property air_vehicle_terminal forsale_lodestar
add_property ams requirement_certification0 false # ground_support
add_property anniversary_gun requirement_certification0 false # medium_assault
add_property ant requirement_certification0 false # vehicles
add_property apc requirement_certification0 false # ground_transport
add_property aphelion_flight requirement_award0 false # bfr_advanced
add_property aphelion_laser requirement_certification0 false # bfr_ai_gunnery
add_property aphelion_starfire requirement_certification0 false # bfr_aa_gunnery
add_property applicator requirement_certification0 false # Medical
add_property aurora requirement_certification0 false # ground_transport
add_property bank requirement_certification0 false # Repair
add_property beamer requirement_certification0 false # standard_assault
add_property bfr_terminal requirement_certification0 false # bfr_basic
add_property bolt_driver requirement_certification0 false # sniper
add_property boomer_trigger requirement_certification0 false # combat_engineering
add_property colossus_burster requirement_certification0 false # bfr_aa_gunnery
add_property colossus_chaingun requirement_certification0 false # bfr_ai_gunnery
add_property colossus_flight requirement_award0 false # bfr_advanced
add_property cycler requirement_certification0 false # medium_assault
add_property cycler_v2 requirement_certification0 false # medium_assault
add_property cycler_v3 requirement_certification0 false # medium_assault
add_property cycler_v4 requirement_certification0 false # medium_assault
add_property delivererv requirement_certification0 false # ground_transport
add_property dropship requirement_certification0 false # air_support
add_property flail requirement_certification0 false # flail
add_property flamethrower requirement_certification0 false # special_assault_2
add_property flechette requirement_certification0 false # medium_assault
add_property fury requirement_certification0 false # quad_all
add_property galaxy_gunship requirement_certification0 false # gunship
add_property gauss requirement_certification0 false # medium_assault
add_property generic_bfr requirement_certification0 false # bfr_basic
add_property heavy_sniper requirement_certification0 false # sniper
add_property hunterseeker requirement_certification0 false # anti_vehicular
add_property ilc9 requirement_certification0 false # standard_assault
add_property isp requirement_certification0 false # standard_assault
add_property katana requirement_award0 false # 2007_fan_faire
add_property lancer requirement_certification0 false # anti_vehicular
add_property lasher requirement_certification0 false # heavy_assault
add_property liberator requirement_certification0 false # air_support
add_property lightgunship requirement_certification0 false # air_cavalry_assault
add_property lightning requirement_certification0 false # armored_assault1
add_property lite_armor requirement_certification0 false # agile_armor
add_property lodestar requirement_certification0 false # air_support
add_property maelstrom requirement_certification0 false # heavy_assault
add_property magrider requirement_certification0 false # armored_assault2
add_property med_armor requirement_certification0 false # reinforced_armor
add_property mediumtransport requirement_certification0 false # ground_transport
add_property mini_chaingun requirement_certification0 false # heavy_assault
add_property mosquito requirement_certification0 false # light_scout
add_property mosquito requirement_certification1 false # air_cavalry_scout
add_property nano_dispenser requirement_certification0 false # Repair
add_property nchev_antiaircraft requirement_certification0 false # max_anti_aircraft
add_property nchev_antiaircraft requirement_certification1 false # max_all
add_property nchev_antipersonnel requirement_certification0 false # max_anti_personnel
add_property nchev_antipersonnel requirement_certification1 false # max_all
add_property nchev_antivehicular requirement_certification0 false # max_anti_vehicular
add_property nchev_antivehicular requirement_certification1 false # max_all
add_property oicw requirement_certification0 false # special_assault_2
add_property pellet_gun requirement_certification0 false # standard_assault
add_property peregrine_flight requirement_award0 false # bfr_advanced
add_property peregrine_mechhammer requirement_certification0 false # bfr_ai_gunnery
add_property peregrine_sparrow requirement_certification0 false # bfr_aa_gunnery
add_property phantasm requirement_certification0 false # phantasm
add_property phoenix requirement_certification0 false # anti_vehicular
add_property prowler requirement_certification0 false # armored_assault2
add_property pulsar requirement_certification0 false # medium_assault
add_property punisher requirement_certification0 false # medium_assault
add_property quadassault requirement_certification0 false # quad_all
add_property quadstealth requirement_certification0 false # quad_all
add_property r_shotgun requirement_certification0 false # heavy_assault
add_property radiator requirement_certification0 false # special_assault
add_property repeater requirement_certification0 false # standard_assault
add_property rocklet requirement_certification0 false # special_assault
add_property router requirement_certification0 false # ground_support
add_property six_shooter requirement_certification0 false # standard_assault
add_property skyguard requirement_certification0 false # assault_buggy
add_property skyguard requirement_certification1 false # light_scout
add_property spiker requirement_certification0 false # medium_assault
add_property standard_issue_armor requirement_certification0 false # empire_issue
add_property stealth_armor requirement_certification0 false # infiltration_suit
add_property striker requirement_certification0 false # anti_vehicular
add_property super_armorkit requirement_award0 false # xmas_spirit
add_property super_medkit requirement_award0 false # xmas_snowman
add_property super_staminakit requirement_award0 false # xmas_gingerman
add_property suppressor requirement_certification0 false # standard_assault
add_property switchblade requirement_certification0 false # switchblade
add_property threemanheavybuggy requirement_certification0 false # assault_buggy
add_property threemanheavybuggy requirement_certification1 false # light_scout
add_property thumper requirement_certification0 false # special_assault
add_property thunderer requirement_certification0 false # ground_transport
add_property trek requirement_certification0 false # virus_hacking
add_property trek requirement_certification1 false # electronics_expert
add_property trhev_antiaircraft requirement_certification0 false # max_anti_aircraft
add_property trhev_antiaircraft requirement_certification1 false # max_all
add_property trhev_antipersonnel requirement_certification0 false # max_anti_personnel
add_property trhev_antipersonnel requirement_certification1 false # max_all
add_property trhev_antivehicular requirement_certification0 false # max_anti_vehicular
add_property trhev_antivehicular requirement_certification1 false # max_all
add_property two_man_assault_buggy requirement_certification0 false # light_scout
add_property two_man_assault_buggy requirement_certification1 false # harasser
add_property two_man_assault_buggy requirement_certification2 false # assault_buggy
add_property twomanheavybuggy requirement_certification0 false # assault_buggy
add_property twomanheavybuggy requirement_certification1 false # light_scout
add_property twomanhoverbuggy requirement_certification0 false # assault_buggy
add_property twomanhoverbuggy requirement_certification1 false # light_scout
add_property twomanhoverbuggy_destroyed requirement_certification0 false # buggy_assault
add_property vanguard requirement_certification0 false # armored_assault2
add_property vehicle_terminal_combined forsale_dropship
add_property vehicle_terminal_combined forsale_galaxy_gunship
add_property vehicle_terminal_combined forsale_lodestar
add_property vshev_antiaircraft requirement_certification0 false # max_anti_aircraft
add_property vshev_antiaircraft requirement_certification1 false # max_all
add_property vshev_antipersonnel requirement_certification0 false # max_anti_personnel
add_property vshev_antipersonnel requirement_certification1 false # max_all
add_property vshev_antivehicular requirement_certification0 false # max_anti_vehicular
add_property vshev_antivehicular requirement_certification1 false # max_all
add_property vulture requirement_award0 false # bomber_ace2
add_property vulture requirement_certification0 false # air_support
add_property wasp requirement_certification0 false # air_cavalry_interceptor
add_property wasp requirement_certification1 false # air_cavalry_interceptor
add_property winchester requirement_certification0 false # standard_assault

View file

@ -0,0 +1,80 @@
add_property ams requirement_certification0 false
add_property anniversary_gun requirement_certification0 false
add_property apc allowed false
add_property apc_nc allowed false
add_property apc_tr allowed false
add_property apc_vs allowed false
add_property aphelion allowed false
add_property aphelion_flight allowed false
add_property aphelion_gunner allowed false
add_property aurora allowed false
add_property battlewagon allowed false
add_property colossus allowed false
add_property colossus_flight allowed false
add_property colossus_gunner allowed false
add_property cycler requirement_certification0 false
add_property delivererv allowed false
add_property dropship requirement_certification0 false
add_property flail allowed false
add_property flechette requirement_certification0 false
add_property fury allowed false
add_property galaxy_gunship allowed false
add_property gauss requirement_certification0 false
add_property heavy_armor allowed false
add_property hunterseeker requirement_certification0 false
add_property lancer requirement_certification0 false
add_property lasher requirement_certification0 false
add_property liberator allowed false
add_property lightgunship allowed false
add_property lightning allowed false
add_property lodestar allowed false
add_property magrider allowed false
add_property mediumtransport allowed false
add_property mini_chaingun requirement_certification0 false
add_property mosquito allowed false
add_property nano_dispenser requirement_certification0 false
add_property nchev allowed false
add_property nchev_antiaircraft allowed false
add_property nchev_antipersonnel allowed false
add_property nchev_antivehicular allowed false
add_property order_terminal forsale_nchev_antiaircraft false
add_property order_terminal forsale_nchev_antipersonnel false
add_property order_terminal forsale_nchev_antivehicular false
add_property order_terminal forsale_trhev_antiaircraft false
add_property order_terminal forsale_trhev_antipersonnel false
add_property order_terminal forsale_trhev_antivehicular false
add_property order_terminal forsale_vshev_antiaircraft false
add_property order_terminal forsale_vshev_antipersonnel false
add_property order_terminal forsale_vshev_antivehicular false
add_property peregrine allowed false
add_property peregrine_flight allowed false
add_property peregrine_gunner allowed false
add_property phantasm purchase_tech_plant false
add_property phantasm requirement_certification0 false
add_property phoenix requirement_certification0 false
add_property prowler allowed false
add_property pulsar requirement_certification0 false
add_property punisher requirement_certification0 false
add_property quadassault allowed false
add_property quadstealth allowed false
add_property r_shotgun requirement_certification0 false
add_property router requirement_certification0 false
add_property skyguard allowed false
add_property striker requirement_certification0 false
add_property switchblade allowed false
add_property threemanheavybuggy allowed false
add_property thunderer allowed false
add_property trhev allowed false
add_property trhev_antiaircraft allowed false
add_property trhev_antipersonnel allowed false
add_property trhev_antivehicular allowed false
add_property two_man_assault_buggy allowed false
add_property twomanheavybuggy allowed false
add_property twomanhoverbuggy allowed false
add_property vanguard allowed false
add_property vshev allowed false
add_property vshev_antiaircraft allowed false
add_property vshev_antipersonnel allowed false
add_property vshev_antivehicular allowed false
add_property vulture allowed false
add_property wasp allowed false

View file

@ -0,0 +1,277 @@
package net.psforever.server
import java.net.InetAddress
import java.nio.file.Paths
import java.util.Locale
import akka.actor.typed.scaladsl.adapter._
import akka.routing.RandomPool
import akka.{actor => classic}
import ch.qos.logback.classic.LoggerContext
import ch.qos.logback.classic.joran.JoranConfigurator
import io.sentry.Sentry
import kamon.Kamon
import net.psforever.actors.session.SessionActor
import net.psforever.crypto.CryptoInterface
import net.psforever.login.psadmin.PsAdminActor
import net.psforever.login._
import net.psforever.objects.Default
import net.psforever.objects.guid.TaskResolver
import net.psforever.objects.zones._
import net.psforever.services.account.{AccountIntermediaryService, AccountPersistenceService}
import net.psforever.services.chat.ChatService
import net.psforever.services.galaxy.GalaxyService
import net.psforever.services.properties.PropertyOverrideManager
import net.psforever.services.teamwork.SquadService
import net.psforever.services.{InterstellarClusterService, ServiceManager}
import net.psforever.util.Config
import net.psforever.zones.Zones
import org.apache.commons.io.FileUtils
import org.flywaydb.core.Flyway
import org.fusesource.jansi.Ansi.Color._
import org.fusesource.jansi.Ansi._
import org.slf4j
import scopt.OParser
object Server {
private val logger = org.log4s.getLogger
case class CliConfig(
command: String = "run",
noAutoMigrate: Boolean = false,
baselineOnMigrate: Boolean = false,
bind: Option[String] = None
)
def printBanner(): Unit = {
println(ansi().fgBright(BLUE).a(""" ___ ________"""))
println(ansi().fgBright(BLUE).a(""" / _ \/ __/ __/__ _______ _ _____ ____"""))
println(ansi().fgBright(MAGENTA).a(""" / ___/\ \/ _// _ \/ __/ -_) |/ / -_) __/"""))
println(ansi().fgBright(RED).a("""/_/ /___/_/ \___/_/ \__/|___/\__/_/""").reset())
println(""" PSForever Server - PSForever Project""")
println(""" http://psforever.net""")
println()
}
def systemInformation: String = {
val processors = Runtime.getRuntime.availableProcessors()
val maxMemory = FileUtils.byteCountToDisplaySize(Runtime.getRuntime.maxMemory())
s"""|~~~ System Information ~~~
|SYS: ${System.getProperty("os.name")} (v. ${System.getProperty("os.version")}, ${System
.getProperty("os.arch")})
|CPU: Detected $processors available logical processor${if (processors != 1) "s" else ""}
|MEM: $maxMemory available to the JVM (tune with -Xmx flag)
|JVM: ${System.getProperty("java.vm.name")} (build ${System.getProperty("java.version")}), ${System.getProperty(
"java.vendor"
)} - ${System.getProperty("java.vendor.url")}
""".stripMargin
}
def run(args: CliConfig): Unit = {
val bindAddress: InetAddress =
args.bind match {
case Some(address) => InetAddress.getByName(address) // address from first argument
case None => InetAddress.getByName(Config.app.bind) // address from config
}
if (Config.app.kamon.enable) {
logger.info("Starting Kamon")
Kamon.init()
}
if (Config.app.sentry.enable) {
logger.info(s"Enabling Sentry")
Sentry.init(Config.app.sentry.dsn)
}
/** Start up the main actor system. This "system" is the home for all actors running on this server */
implicit val system = classic.ActorSystem("PsLogin")
Default(system)
/** Create pipelines for the login and world servers
*
* The first node in the pipe is an Actor that handles the crypto for protecting packets.
* After any crypto operations have been applied or unapplied, the packets are passed on to the next
* actor in the chain. For an incoming packet, this is a player session handler. For an outgoing packet
* this is the session router, which returns the packet to the sending host.
*
* See SessionRouter.scala for a diagram
*/
val loginTemplate = List(
SessionPipeline("crypto-session-", classic.Props[CryptoSessionActor]()),
SessionPipeline("packet-session-", classic.Props[PacketCodingActor]()),
SessionPipeline("login-session-", classic.Props[LoginSessionActor]())
)
val worldTemplate = List(
SessionPipeline("crypto-session-", classic.Props[CryptoSessionActor]()),
SessionPipeline("packet-session-", classic.Props[PacketCodingActor]()),
SessionPipeline("world-session-", classic.Props[SessionActor]())
)
val netSim: Option[NetworkSimulatorParameters] = if (Config.app.developer.netSim.enable) {
val params = NetworkSimulatorParameters(
Config.app.developer.netSim.loss,
Config.app.developer.netSim.delay.toMillis,
Config.app.developer.netSim.reorderChance,
Config.app.developer.netSim.reorderTime.toMillis
)
logger.warn("NetSim is active")
logger.warn(params.toString)
Some(params)
} else {
None
}
val zones = Zones.zones ++ Seq(Zone.Nowhere)
system.spawn(ChatService(), ChatService.ChatServiceKey.id)
system.spawn(InterstellarClusterService(zones), InterstellarClusterService.InterstellarClusterServiceKey.id)
val serviceManager = ServiceManager.boot
serviceManager ! ServiceManager.Register(classic.Props[AccountIntermediaryService](), "accountIntermediary")
serviceManager ! ServiceManager.Register(RandomPool(150).props(classic.Props[TaskResolver]()), "taskResolver")
serviceManager ! ServiceManager.Register(classic.Props[GalaxyService](), "galaxy")
serviceManager ! ServiceManager.Register(classic.Props[SquadService](), "squad")
serviceManager ! ServiceManager.Register(classic.Props[AccountPersistenceService](), "accountPersistence")
serviceManager ! ServiceManager.Register(classic.Props[PropertyOverrideManager](), "propertyOverrideManager")
val loginRouter = classic.Props(new SessionRouter("Login", loginTemplate))
val worldRouter = classic.Props(new SessionRouter("World", worldTemplate))
val loginListener = system.actorOf(
classic.Props(new UdpListener(loginRouter, "login-session-router", bindAddress, Config.app.login.port, netSim)),
"login-udp-endpoint"
)
val worldListener = system.actorOf(
classic.Props(new UdpListener(worldRouter, "world-session-router", bindAddress, Config.app.world.port, netSim)),
"world-udp-endpoint"
)
val adminListener = system.actorOf(
classic.Props(
new TcpListener(
classOf[PsAdminActor],
"net.psforever.login.psadmin-client-",
InetAddress.getByName(Config.app.admin.bind),
Config.app.admin.port
)
),
"net.psforever.login.psadmin-tcp-endpoint"
)
logger.info(
s"Login server is running on ${InetAddress.getByName(Config.app.public).getHostAddress}:${Config.app.login.port}"
)
// Add our shutdown hook (this works for Control+C as well, but not in Cygwin)
sys addShutdownHook {
// TODO: clean up active sessions and close resources safely
logger.info("Login server now shutting down...")
}
}
def flyway(args: CliConfig): Flyway = {
Flyway
.configure()
.dataSource(Config.app.database.toJdbc, Config.app.database.username, Config.app.database.password)
.baselineOnMigrate(args.baselineOnMigrate)
.load()
}
def migrate(args: CliConfig): Unit = {
flyway(args).migrate()
}
def main(args: Array[String]): Unit = {
Locale.setDefault(Locale.US); // to have floats with dots, not comma
printBanner()
println(systemInformation)
val loggerConfigPath = Paths.get(Config.directory, "logback.xml").toAbsolutePath.toString
val loggerContext = slf4j.LoggerFactory.getILoggerFactory.asInstanceOf[LoggerContext]
val configurator = new JoranConfigurator()
configurator.setContext(loggerContext)
loggerContext.reset()
configurator.doConfigure(loggerConfigPath)
Config.result match {
case Left(failures) =>
logger.error("Loading config failed")
failures.toList.foreach { failure =>
logger.error(failure.toString)
}
sys.exit(1)
case Right(_) =>
}
/** Initialize the PSCrypto native library
*
* PSCrypto provides PlanetSide specific crypto that is required to communicate with it.
* It has to be distributed as a native library because there is no Scala version of the required
* cryptographic primitives (MD5MAC). See https://github.com/psforever/PSCrypto for more information.
*/
try {
CryptoInterface.initialize()
} catch {
case e: UnsatisfiedLinkError =>
logger.error("Unable to initialize " + CryptoInterface.libName)
logger.error(e)(
"This means that your PSCrypto version is out of date. Get the latest version from the README" +
" https://github.com/psforever/PSF-LoginServer#downloading-pscrypto"
)
sys.exit(1)
case e: IllegalArgumentException =>
logger.error("Unable to initialize " + CryptoInterface.libName)
logger.error(e)(
"This means that your PSCrypto version is out of date. Get the latest version from the README" +
" https://github.com/psforever/PSF-LoginServer#downloading-pscrypto"
)
sys.exit(1)
}
val builder = OParser.builder[CliConfig]
val parser = {
import builder._
OParser.sequence(
programName("psforever-server"),
opt[Unit]("no-auto-migrate")
.action((_, c) => c.copy(noAutoMigrate = true))
.text("Do not auto migrate database."),
opt[Unit]("baseline-on-migrate")
.action((_, c) => c.copy(baselineOnMigrate = true))
.text("Automatically baseline existing databases."),
cmd("run")
.action((_, c) => c.copy(command = "run"))
.text("Run server.")
.children(
opt[String]("bind")
.action((x, c) => c.copy(bind = Some(x)))
.text("Bind address")
),
cmd("migrate")
.action((_, c) => c.copy(command = "migrate"))
.text("Apply database migrations.")
)
}
OParser.parse(parser, args, CliConfig()) match {
case Some(config) =>
config.command match {
case "run" =>
if (config.noAutoMigrate) {
flyway(config).validate()
} else {
migrate(config)
}
run(config)
case "migrate" =>
migrate(config)
}
case _ =>
sys.exit(1)
}
}
}

View file

@ -0,0 +1,11 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="ERROR">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View file

@ -0,0 +1,21 @@
# This is a comment
[default]
string = a string
string_quoted = "a string"
int = 31
time = 1 second
time2 = 100 milliseconds
float = 0.1
bool_true = yes
bool_false = no
enum_dog = Dog
# missing
[bad]
bad_int = not a number
bad_time = 10
bad_float = A
bad_bool = dunno
bad_int_range = -1
bad_int_range2 = 3
bad_enum = Tree

View file

@ -0,0 +1,48 @@
package net.psforever.pslogin
import akka.actor.{ActorRef, MDCContextAware}
import akka.testkit.TestProbe
import net.psforever.login.HelloFriend
import net.psforever.packet.{ControlPacket, GamePacket}
final case class MDCGamePacket(packet: GamePacket)
final case class MDCControlPacket(packet: ControlPacket)
class MDCTestProbe(probe: TestProbe) extends MDCContextAware {
/*
The way this test mediator works needs to be explained.
MDCContextAware objects initialize themselves in a chain of ActorRefs defined in the HelloFriend message.
As the iterator is consumed, it produces a right-neighbor (r-neighbor) that is much further along the chain.
The HelloFriend is passed to that r-neighbor and that is how subsequent neighbors are initialized and chained.
MDCContextAware objects consume and produce internal messages called MdcMsg that wrap around the payload.
Normally inaccessible from the outside, the payload is unwrapped within the standard receive PartialFunction.
By interacting with a TestProbe constructor param, information that would be concealed by MdcMsg can be polled.
The l-neighbor of the MDCContextAware is the system of the base.actor.base.ActorTest TestKit.
The r-neighbor of the MDCContextAware is this MDCTestProbe and, indirectly, the TestProbe that was interjected.
Pass l-input into the MDCContextAware itself.
The r-output is a normal message that can be polled on that TestProbe.
Pass r-input into this MDCTestProbe directly.
The l-output is an MdcMsg that can be treated just as r-output, sending it to this Actor and polling the TestProbe.
*/
private var left: ActorRef = ActorRef.noSender
def receive: Receive = {
case msg @ HelloFriend(_, _) =>
left = sender()
probe.ref ! msg
case MDCGamePacket(msg) =>
left ! msg
case MDCControlPacket(msg) =>
left ! msg
case msg =>
left ! msg
probe.ref ! msg
}
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,32 @@
// Copyright (c) 2017 PSForever
package actor.base
import akka.actor.ActorSystem
import akka.testkit.{ImplicitSender, TestKit}
import com.typesafe.config.ConfigFactory
import org.scalatest.BeforeAndAfterAll
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpecLike
import org.specs2.specification.Scope
abstract class ActorTest(sys: ActorSystem = ActorSystem("system", ConfigFactory.parseMap(ActorTest.LoggingConfig)))
extends TestKit(sys)
with Scope
with ImplicitSender
with AnyWordSpecLike
with Matchers
with BeforeAndAfterAll {
override def afterAll(): Unit = {
TestKit.shutdownActorSystem(system)
}
}
object ActorTest {
import scala.jdk.CollectionConverters._
private val LoggingConfig = Map(
"akka.loggers" -> List("akka.testkit.TestEventListener").asJava,
"akka.loglevel" -> "OFF",
"akka.stdout-loglevel" -> "OFF",
"akka.log-dead-letters" -> "OFF"
).asJava
}

View file

@ -0,0 +1,258 @@
// Copyright (c) 2017 PSForever
package actor.objects
import akka.actor.{ActorRef, ActorSystem, Props}
import akka.testkit.TestProbe
import actor.base.ActorTest
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
import net.psforever.objects.serverobject.structures.StructureType
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle}
import net.psforever.objects.zones.Zone
import net.psforever.types.{PlanetSideGUID, _}
import net.psforever.services.RemoverActor
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import akka.actor.typed.scaladsl.adapter._
import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.avatar.Avatar
import scala.concurrent.duration._
class VehicleSpawnControl1Test extends ActorTest {
"VehicleSpawnControl" should {
"construct" in {
val obj = VehicleSpawnPad(GlobalDefinitions.mb_pad_creation)
obj.Actor = system.actorOf(Props(classOf[VehicleSpawnControl], obj), "mb_pad_creation")
assert(obj.Actor != ActorRef.noSender)
}
}
}
class VehicleSpawnControl2Test extends ActorTest {
"VehicleSpawnControl" should {
"complete a vehicle order" in {
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
val probe = new TestProbe(system, "zone-events")
zone.VehicleEvents = probe.ref //zone events
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
vehicle.Seats(0).Occupant = player
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.PlayerSeatedInVehicle])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ServerVehicleOverrideStart])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ServerVehicleOverrideEnd])
//if we move the vehicle away from the pad, we should receive a ResetSpawnPad message
//that means that the first order has cleared and the spawn pad is now waiting for additional orders
vehicle.Position = Vector3(12, 0, 0)
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ResetSpawnPad])
}
}
}
class VehicleSpawnControl3Test extends ActorTest {
"VehicleSpawnControl" should {
"block the second vehicle order until the first is completed" in {
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
//we can recycle the vehicle and the player for each order
val probe = new TestProbe(system, "zone-events")
val player2 = Player(Avatar(0, "test2", player.Faction, CharacterGender.Male, 0, CharacterVoice.Mute))
player2.GUID = PlanetSideGUID(11)
player2.Continent = zone.id
player2.Spawn()
zone.VehicleEvents = probe.ref //zone events
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //first order
pad.Actor ! VehicleSpawnPad.VehicleOrder(player2, vehicle) //second order (vehicle shared)
assert(probe.receiveOne(1 seconds) match {
case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Queue, _) => true
case _ => false
})
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
vehicle.Seats(0).Occupant = player
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.PlayerSeatedInVehicle])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ServerVehicleOverrideStart])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ServerVehicleOverrideEnd])
assert(probe.receiveOne(1 minute) match {
case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true
case _ => false
})
assert(probe.receiveOne(1 minute) match {
case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true
case _ => false
})
//if we move the vehicle away from the pad, we should receive a second ConcealPlayer message
//that means that the first order has cleared and the spawn pad is now working on the second order successfully
player.VehicleSeated = None //since shared between orders, as necessary
vehicle.Seats(0).Occupant = None
vehicle.Position = Vector3(12, 0, 0)
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ResetSpawnPad])
probe.expectMsgClass(3 seconds, classOf[VehicleSpawnPad.ConcealPlayer])
}
}
}
class VehicleSpawnControl4Test extends ActorTest {
"VehicleSpawnControl" should {
"clean up the vehicle if the driver-to-be is on the wrong continent" in {
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
val probe = new TestProbe(system, "zone-events")
zone.VehicleEvents = probe.ref
player.Continent = "problem" //problem
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order
val msg = probe.receiveOne(1 minute)
assert(
msg match {
case VehicleServiceMessage.Decon(RemoverActor.AddTask(v, z, _)) => (v == vehicle) && (z == zone)
case _ => false
}
)
probe.expectNoMessage(5 seconds)
}
}
}
class VehicleSpawnControl5Test extends ActorTest() {
"VehicleSpawnControl" should {
"abandon a destroyed vehicle on the spawn pad (blocking)" in {
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
val probe = new TestProbe(system, "zone-events")
zone.VehicleEvents = probe.ref
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle])
vehicle.Health = 0 //problem
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer])
assert(probe.receiveOne(1 minute) match {
case VehicleServiceMessage(_, VehicleAction.LoadVehicle(_, _, _, _, _)) => true
case _ => false
})
assert(probe.receiveOne(1 minute) match {
case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true
case _ => false
})
}
}
}
class VehicleSpawnControl6Test extends ActorTest() {
"VehicleSpawnControl" should {
"abandon a vehicle on the spawn pad if driver is unfit to drive (blocking)" in {
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
val probe = new TestProbe(system, "zone-events")
zone.VehicleEvents = probe.ref
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle])
player.Die
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer])
assert(probe.receiveOne(1 minute) match {
case VehicleServiceMessage(_, VehicleAction.LoadVehicle(_, _, _, _, _)) => true
case _ => false
})
assert(probe.receiveOne(1 minute) match {
case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true
case _ => false
})
}
}
}
class VehicleSpawnControl7Test extends ActorTest {
"VehicleSpawnControl" should {
"abandon a vehicle on the spawn pad if driver is unfit to drive (blocking)" in {
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
val probe = new TestProbe(system, "zone-events")
player.ExoSuit = ExoSuitType.MAX
zone.VehicleEvents = probe.ref //zone events
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer])
assert(probe.receiveOne(1 minute) match {
case VehicleServiceMessage(_, VehicleAction.LoadVehicle(_, _, _, _, _)) => true
case _ => false
})
assert(probe.receiveOne(1 minute) match {
case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true
case _ => false
})
}
}
}
object VehicleSpawnPadControlTest {
import net.psforever.objects.zones.ZoneMap
private val map = new ZoneMap("test-map")
def SetUpAgents(
faction: PlanetSideEmpire.Value
)(implicit system: ActorSystem): (Vehicle, Player, VehicleSpawnPad, Zone) = {
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.vehicles.VehicleControl
import net.psforever.objects.Tool
import net.psforever.types.CharacterGender
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
val weapon = vehicle.WeaponControlledFromSeat(1).get.asInstanceOf[Tool]
val guid: NumberPoolHub = new NumberPoolHub(LimitedNumberSource(5))
guid.AddPool("test-pool", (0 to 5).toList)
guid.register(vehicle, "test-pool")
guid.register(weapon, "test-pool")
guid.register(weapon.AmmoSlot.Box, "test-pool")
val zone = new Zone("test-zone", map, 0) {
override def SetupNumberPools(): Unit = {}
}
zone.GUID(guid)
zone.actor = system.spawn(ZoneActor(zone), s"test-zone-${System.nanoTime()}")
// Hack: Wait for the Zone to finish booting, otherwise later tests will fail randomly due to race conditions
// with actor probe setting
// TODO(chord): Remove when Zone supports notification of booting being complete
Thread.sleep(5000)
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), s"vehicle-control-${System.nanoTime()}")
val pad = VehicleSpawnPad(GlobalDefinitions.mb_pad_creation)
pad.Actor = system.actorOf(Props(classOf[VehicleSpawnControl], pad), s"test-pad-${System.nanoTime()}")
pad.Owner =
new Building("Building", building_guid = 0, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
pad.Owner.Faction = faction
pad.Zone = zone
guid.register(pad, "test-pool")
val player = Player(Avatar(0, "test", faction, CharacterGender.Male, 0, CharacterVoice.Mute))
guid.register(player, "test-pool")
player.Zone = zone
player.Spawn()
//note: pad and vehicle are both at Vector3(1,0,0) so they count as blocking
pad.Position = Vector3(1, 0, 0)
vehicle.Position = Vector3(1, 0, 0)
(vehicle, player, pad, zone)
}
}

View file

@ -0,0 +1,674 @@
// Copyright (c) 2017 PSForever
package actor.service
import akka.actor.Props
import akka.routing.RandomPool
import actor.base.ActorTest
import net.psforever.objects._
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.packet.game.objectcreate.{DroppedItemData, ObjectClass, ObjectCreateMessageParent, PlacementData}
import net.psforever.packet.game.{ObjectCreateMessage, PlayerStateMessageUpstream}
import net.psforever.types._
import net.psforever.services.{RemoverActor, Service, ServiceManager}
import net.psforever.services.avatar._
import scala.concurrent.duration._
import akka.actor.typed.scaladsl.adapter._
import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.avatar.Avatar
class AvatarService1Test extends ActorTest {
"AvatarService" should {
"construct" in {
ServiceManager.boot(system)
system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
assert(true)
}
}
}
class AvatarService2Test extends ActorTest {
"AvatarService" should {
"subscribe" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
assert(true)
}
}
}
class AvatarService3Test extends ActorTest {
"AvatarService" should {
ServiceManager.boot(system)
"subscribe to a specific channel" in {
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! Service.Leave()
assert(true)
}
}
}
class AvatarService4Test extends ActorTest {
"AvatarService" should {
"subscribe" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! Service.LeaveAll()
assert(true)
}
}
}
class AvatarService5Test extends ActorTest {
"AvatarService" should {
"pass an unhandled message" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! "hello"
expectNoMessage()
}
}
}
class ArmorChangedTest extends ActorTest {
"AvatarService" should {
"pass ArmorChanged" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.ArmorChanged(PlanetSideGUID(10), ExoSuitType.Reinforced, 0))
expectMsg(
AvatarServiceResponse(
"/test/Avatar",
PlanetSideGUID(10),
AvatarResponse.ArmorChanged(ExoSuitType.Reinforced, 0)
)
)
}
}
}
class ConcealPlayerTest extends ActorTest {
"AvatarService" should {
"pass ConcealPlayer" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.ConcealPlayer(PlanetSideGUID(10)))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ConcealPlayer()))
}
}
}
class EquipmentInHandTest extends ActorTest {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), "release-test-service")
val toolDef = GlobalDefinitions.beamer
val tool = Tool(toolDef)
tool.GUID = PlanetSideGUID(40)
tool.AmmoSlots.head.Box.GUID = PlanetSideGUID(41)
val pkt = ObjectCreateMessage(
toolDef.ObjectId,
tool.GUID,
ObjectCreateMessageParent(PlanetSideGUID(11), 2),
toolDef.Packet.ConstructorData(tool).get
)
"AvatarService" should {
"pass EquipmentInHand" in {
service ! Service.Join("test")
service ! AvatarServiceMessage(
"test",
AvatarAction.EquipmentInHand(PlanetSideGUID(10), PlanetSideGUID(11), 2, tool)
)
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.EquipmentInHand(pkt)))
}
}
}
class DeployItemTest extends ActorTest {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), "deploy-item-test-service")
val objDef = GlobalDefinitions.motionalarmsensor
val obj = new SensorDeployable(objDef)
obj.Position = Vector3(1, 2, 3)
obj.Orientation = Vector3(4, 5, 6)
obj.GUID = PlanetSideGUID(40)
val pkt = ObjectCreateMessage(
objDef.ObjectId,
obj.GUID,
objDef.Packet.ConstructorData(obj).get
)
"AvatarService" should {
"pass DeployItem" in {
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.DeployItem(PlanetSideGUID(10), obj))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.DropItem(pkt)))
}
}
}
class DroptItemTest extends ActorTest {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), "release-test-service")
val toolDef = GlobalDefinitions.beamer
val tool = Tool(toolDef)
tool.Position = Vector3(1, 2, 3)
tool.Orientation = Vector3(4, 5, 6)
tool.GUID = PlanetSideGUID(40)
tool.AmmoSlots.head.Box.GUID = PlanetSideGUID(41)
val pkt = ObjectCreateMessage(
toolDef.ObjectId,
tool.GUID,
DroppedItemData(
PlacementData(tool.Position, tool.Orientation),
toolDef.Packet.ConstructorData(tool).get
)
)
"AvatarService" should {
"pass DropItem" in {
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.DropItem(PlanetSideGUID(10), tool))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.DropItem(pkt)))
}
}
}
class LoadPlayerTest extends ActorTest {
val obj = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1))
obj.GUID = PlanetSideGUID(10)
obj.Slot(5).Equipment.get.GUID = PlanetSideGUID(11)
val c1data = obj.Definition.Packet.DetailedConstructorData(obj).get
val pkt1 = ObjectCreateMessage(ObjectClass.avatar, PlanetSideGUID(10), c1data)
val parent = ObjectCreateMessageParent(PlanetSideGUID(12), 0)
obj.VehicleSeated = PlanetSideGUID(12)
val c2data = obj.Definition.Packet.DetailedConstructorData(obj).get
val pkt2 = ObjectCreateMessage(ObjectClass.avatar, PlanetSideGUID(10), parent, c2data)
"AvatarService" should {
"pass LoadPlayer" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
//no parent data
service ! AvatarServiceMessage(
"test",
AvatarAction.LoadPlayer(PlanetSideGUID(20), ObjectClass.avatar, PlanetSideGUID(10), c1data, None)
)
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(20), AvatarResponse.LoadPlayer(pkt1)))
//parent data
service ! AvatarServiceMessage(
"test",
AvatarAction.LoadPlayer(PlanetSideGUID(20), ObjectClass.avatar, PlanetSideGUID(10), c2data, Some(parent))
)
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(20), AvatarResponse.LoadPlayer(pkt2)))
}
}
}
class ObjectDeleteTest extends ActorTest {
"AvatarService" should {
"pass ObjectDelete" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.ObjectDelete(PlanetSideGUID(10), PlanetSideGUID(11)))
expectMsg(
AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectDelete(PlanetSideGUID(11), 0))
)
service ! AvatarServiceMessage("test", AvatarAction.ObjectDelete(PlanetSideGUID(10), PlanetSideGUID(11), 55))
expectMsg(
AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectDelete(PlanetSideGUID(11), 55))
)
}
}
}
class ObjectHeldTest extends ActorTest {
"AvatarService" should {
"pass ObjectHeld" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.ObjectHeld(PlanetSideGUID(10), 1))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectHeld(1)))
}
}
}
class PutDownFDUTest extends ActorTest {
"AvatarService" should {
"pass PutDownFDU" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.PutDownFDU(PlanetSideGUID(10)))
expectMsg(
AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.PutDownFDU(PlanetSideGUID(10)))
)
}
}
}
class PlanetsideAttributeTest extends ActorTest {
"AvatarService" should {
"pass PlanetsideAttribute" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.PlanetsideAttribute(PlanetSideGUID(10), 5, 1200L))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.PlanetsideAttribute(5, 1200L)))
}
}
}
class PlayerStateTest extends ActorTest {
val msg = PlayerStateMessageUpstream(
PlanetSideGUID(75),
Vector3(3694.1094f, 2735.4531f, 90.84375f),
Some(Vector3(4.375f, 2.59375f, 0.0f)),
61.875f,
351.5625f,
0.0f,
136,
0,
false,
false,
false,
false,
112,
0
)
"AvatarService" should {
"pass PlayerState" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage(
"test",
AvatarAction.PlayerState(
PlanetSideGUID(10),
Vector3(3694.1094f, 2735.4531f, 90.84375f),
Some(Vector3(4.375f, 2.59375f, 0.0f)),
61.875f,
351.5625f,
0.0f,
136,
false,
false,
false,
false,
false,
false
)
)
expectMsg(
AvatarServiceResponse(
"/test/Avatar",
PlanetSideGUID(10),
AvatarResponse.PlayerState(
Vector3(3694.1094f, 2735.4531f, 90.84375f),
Some(Vector3(4.375f, 2.59375f, 0.0f)),
61.875f,
351.5625f,
0.0f,
136,
false,
false,
false,
false,
false,
false
)
)
)
}
}
}
class PickupItemTest extends ActorTest {
val obj = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1))
val tool = Tool(GlobalDefinitions.beamer)
tool.GUID = PlanetSideGUID(40)
"pass PickUpItem" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.PickupItem(PlanetSideGUID(10), tool))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectDelete(tool.GUID, 0)))
}
}
class ReloadTest extends ActorTest {
"AvatarService" should {
"pass Reload" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.Reload(PlanetSideGUID(10), PlanetSideGUID(40)))
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.Reload(PlanetSideGUID(40))))
}
}
}
class ChangeAmmoTest extends ActorTest {
val ammoDef = GlobalDefinitions.energy_cell
val ammoBox = AmmoBox(ammoDef)
"AvatarService" should {
"pass ChangeAmmo" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage(
"test",
AvatarAction.ChangeAmmo(
PlanetSideGUID(10),
PlanetSideGUID(40),
0,
PlanetSideGUID(40),
ammoDef.ObjectId,
PlanetSideGUID(41),
ammoDef.Packet.ConstructorData(ammoBox).get
)
)
expectMsg(
AvatarServiceResponse(
"/test/Avatar",
PlanetSideGUID(10),
AvatarResponse.ChangeAmmo(
PlanetSideGUID(40),
0,
PlanetSideGUID(40),
ammoDef.ObjectId,
PlanetSideGUID(41),
ammoDef.Packet.ConstructorData(ammoBox).get
)
)
)
}
}
}
class ChangeFireModeTest extends ActorTest {
val ammoDef = GlobalDefinitions.energy_cell
val ammoBox = AmmoBox(ammoDef)
"AvatarService" should {
"pass ChangeFireMode" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.ChangeFireMode(PlanetSideGUID(10), PlanetSideGUID(40), 0))
expectMsg(
AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ChangeFireMode(PlanetSideGUID(40), 0))
)
}
}
}
class ChangeFireStateStartTest extends ActorTest {
"AvatarService" should {
"pass ChangeFireState_Start" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.ChangeFireState_Start(PlanetSideGUID(10), PlanetSideGUID(40)))
expectMsg(
AvatarServiceResponse(
"/test/Avatar",
PlanetSideGUID(10),
AvatarResponse.ChangeFireState_Start(PlanetSideGUID(40))
)
)
}
}
}
class ChangeFireStateStopTest extends ActorTest {
"AvatarService" should {
"pass ChangeFireState_Stop" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.ChangeFireState_Stop(PlanetSideGUID(10), PlanetSideGUID(40)))
expectMsg(
AvatarServiceResponse(
"/test/Avatar",
PlanetSideGUID(10),
AvatarResponse.ChangeFireState_Stop(PlanetSideGUID(40))
)
)
}
}
}
class WeaponDryFireTest extends ActorTest {
"AvatarService" should {
"pass WeaponDryFire" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage("test", AvatarAction.WeaponDryFire(PlanetSideGUID(10), PlanetSideGUID(40)))
expectMsg(
AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.WeaponDryFire(PlanetSideGUID(40)))
)
}
}
}
class AvatarStowEquipmentTest extends ActorTest {
val tool = Tool(GlobalDefinitions.beamer)
"AvatarService" should {
"pass StowEquipment" in {
ServiceManager.boot(system)
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
service ! Service.Join("test")
service ! AvatarServiceMessage(
"test",
AvatarAction.StowEquipment(PlanetSideGUID(10), PlanetSideGUID(11), 2, tool)
)
expectMsg(
AvatarServiceResponse(
"/test/Avatar",
PlanetSideGUID(10),
AvatarResponse.StowEquipment(PlanetSideGUID(11), 2, tool)
)
)
}
}
}
/*
Preparation for these three Release tests is involved.
The ServiceManager must not only be set up correctly, but must be given a TaskResolver.
The AvatarService is started and that starts CorpseRemovalActor, an essential part of this test.
The CorpseRemovalActor needs that TaskResolver created by the ServiceManager;
but, another independent TaskResolver will be needed for manual parts of the test.
(The ServiceManager's TaskResolver can be "borrowed" but that requires writing code to intercept it.)
The Zone needs to be set up and initialized properly with a ZoneActor.
The ZoneActor builds the GUID Actor and the ZonePopulationActor.
ALL of these Actors will talk to each other.
The lines of communication can short circuit if the next Actor does not have the correct information.
Putting Actor startup in the main class, outside of the body of the test, helps.
Frequent pauses to allow everything to sort their messages also helps.
Even with all this work, the tests have a high chance of failure just due to being asynchronous.
*/
class AvatarReleaseTest extends ActorTest {
ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]()), "taskResolver")
val zone = new Zone("test", new ZoneMap("test-map"), 0) {
override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) }
}
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
val taskResolver = system.actorOf(Props[TaskResolver](), "release-test-resolver")
zone.actor = system.spawn(ZoneActor(zone), "release-test-zone")
val obj = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1))
obj.Continent = "test"
obj.Release
"AvatarService" should {
"pass Release" in {
expectNoMessage(100 milliseconds) //spacer
service ! Service.Join("test")
taskResolver ! GUIDTask.RegisterObjectTask(obj)(zone.GUID)
assert(zone.Corpses.isEmpty)
zone.Population ! Zone.Corpse.Add(obj)
expectNoMessage(200 milliseconds) //spacer
assert(zone.Corpses.size == 1)
assert(obj.HasGUID)
val guid = obj.GUID
service ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone, Some(1 second))) //alive for one second
val reply1 = receiveOne(200 milliseconds)
assert(reply1.isInstanceOf[AvatarServiceResponse])
val reply1msg = reply1.asInstanceOf[AvatarServiceResponse]
assert(reply1msg.channel == "/test/Avatar")
assert(reply1msg.avatar_guid == guid)
assert(reply1msg.replyMessage.isInstanceOf[AvatarResponse.Release])
assert(reply1msg.replyMessage.asInstanceOf[AvatarResponse.Release].player == obj)
val reply2 = receiveOne(2 seconds)
assert(reply2.isInstanceOf[AvatarServiceResponse])
val reply2msg = reply2.asInstanceOf[AvatarServiceResponse]
assert(reply2msg.channel.equals("/test/Avatar"))
assert(reply2msg.avatar_guid == Service.defaultPlayerGUID)
assert(reply2msg.replyMessage.isInstanceOf[AvatarResponse.ObjectDelete])
assert(reply2msg.replyMessage.asInstanceOf[AvatarResponse.ObjectDelete].item_guid == guid)
expectNoMessage(1 seconds)
assert(zone.Corpses.isEmpty)
assert(!obj.HasGUID)
}
}
}
class AvatarReleaseEarly1Test extends ActorTest {
ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]()), "taskResolver")
val zone = new Zone("test", new ZoneMap("test-map"), 0) {
override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) }
}
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
val taskResolver = system.actorOf(Props[TaskResolver](), "release-test-resolver")
zone.actor = system.spawn(ZoneActor(zone), "release-test-zone")
val obj = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1))
obj.Continent = "test"
obj.Release
"AvatarService" should {
"pass Release" in {
expectNoMessage(100 milliseconds) //spacer
service ! Service.Join("test")
taskResolver ! GUIDTask.RegisterObjectTask(obj)(zone.GUID)
assert(zone.Corpses.isEmpty)
zone.Population ! Zone.Corpse.Add(obj)
expectNoMessage(200 milliseconds) //spacer
assert(zone.Corpses.size == 1)
assert(obj.HasGUID)
val guid = obj.GUID
service ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone)) //3+ minutes!
val reply1 = receiveOne(200 milliseconds)
assert(reply1.isInstanceOf[AvatarServiceResponse])
val reply1msg = reply1.asInstanceOf[AvatarServiceResponse]
assert(reply1msg.channel == "/test/Avatar")
assert(reply1msg.avatar_guid == guid)
assert(reply1msg.replyMessage.isInstanceOf[AvatarResponse.Release])
assert(reply1msg.replyMessage.asInstanceOf[AvatarResponse.Release].player == obj)
service ! AvatarServiceMessage.Corpse(RemoverActor.HurrySpecific(List(obj), zone)) //IMPORTANT: ONE ENTRY
val reply2 = receiveOne(200 milliseconds)
assert(reply2.isInstanceOf[AvatarServiceResponse])
val reply2msg = reply2.asInstanceOf[AvatarServiceResponse]
assert(reply2msg.channel.equals("/test/Avatar"))
assert(reply2msg.avatar_guid == Service.defaultPlayerGUID)
assert(reply2msg.replyMessage.isInstanceOf[AvatarResponse.ObjectDelete])
assert(reply2msg.replyMessage.asInstanceOf[AvatarResponse.ObjectDelete].item_guid == guid)
expectNoMessage(1 seconds)
assert(zone.Corpses.isEmpty)
assert(!obj.HasGUID)
}
}
}
class AvatarReleaseEarly2Test extends ActorTest {
ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]()), "taskResolver")
val zone = new Zone("test", new ZoneMap("test-map"), 0) {
override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) }
}
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
val taskResolver = system.actorOf(Props[TaskResolver](), "release-test-resolver")
zone.actor = system.spawn(ZoneActor(zone), "release-test-zone")
val objAlt =
Player(
Avatar(0, "TestCharacter2", PlanetSideEmpire.NC, CharacterGender.Male, 1, CharacterVoice.Voice1)
) //necessary clutter
val obj = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1))
obj.Continent = "test"
obj.Release
"AvatarService" should {
"pass Release" in {
expectNoMessage(100 milliseconds) //spacer
service ! Service.Join("test")
taskResolver ! GUIDTask.RegisterObjectTask(obj)(zone.GUID)
assert(zone.Corpses.isEmpty)
zone.Population ! Zone.Corpse.Add(obj)
expectNoMessage(200 milliseconds) //spacer
assert(zone.Corpses.size == 1)
assert(obj.HasGUID)
val guid = obj.GUID
service ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone)) //3+ minutes!
val reply1 = receiveOne(200 milliseconds)
assert(reply1.isInstanceOf[AvatarServiceResponse])
val reply1msg = reply1.asInstanceOf[AvatarServiceResponse]
assert(reply1msg.channel == "/test/Avatar")
assert(reply1msg.avatar_guid == guid)
assert(reply1msg.replyMessage.isInstanceOf[AvatarResponse.Release])
assert(reply1msg.replyMessage.asInstanceOf[AvatarResponse.Release].player == obj)
service ! AvatarServiceMessage.Corpse(
RemoverActor.HurrySpecific(List(objAlt, obj), zone)
) //IMPORTANT: TWO ENTRIES
val reply2 = receiveOne(100 milliseconds)
assert(reply2.isInstanceOf[AvatarServiceResponse])
val reply2msg = reply2.asInstanceOf[AvatarServiceResponse]
assert(reply2msg.channel.equals("/test/Avatar"))
assert(reply2msg.avatar_guid == Service.defaultPlayerGUID)
assert(reply2msg.replyMessage.isInstanceOf[AvatarResponse.ObjectDelete])
assert(reply2msg.replyMessage.asInstanceOf[AvatarResponse.ObjectDelete].item_guid == guid)
expectNoMessage(1 seconds)
assert(zone.Corpses.isEmpty)
assert(!obj.HasGUID)
}
}
}
object AvatarServiceTest {
import java.util.concurrent.atomic.AtomicInteger
private val number = new AtomicInteger(1)
def TestName: String = {
s"service${number.getAndIncrement()}"
}
}