Merged in Obique/holocore (pull request #662)

Quality assurance
This commit is contained in:
Obique PSWG
2019-10-09 06:42:25 +00:00
33 changed files with 2521 additions and 2390 deletions
+1
View File
@@ -73,6 +73,7 @@ dependencies {
utilityCompile project(':pswgcommon')
utilityCompile sourceSets.main.output
utilityCompile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: '1.3.50'
utilityCompile group: 'org.xerial', name: 'sqlite-jdbc', version: '3.23.1'
utilityCompile group: 'org.mongodb', name: 'mongo-java-driver', version: '3.6.3'
utilityCompile group: 'me.joshlarson', name: "fast-json", version: '3.0.0'
File diff suppressed because it is too large Load Diff
+1 -30
View File
@@ -1075,33 +1075,6 @@ item_ithorian_gloves_02_01 object/tangible/wearables/ithorian/ith_gloves_s02.iff
item_ithorian_pants_02_01 object/tangible/wearables/ithorian/ith_pants_s19.iff wearable Issued Ithorian Pants 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 agility_modified=3 -1 6 63 -1 45 0 0 npe clothing
item_ithorian_shirt_02_01 object/tangible/wearables/ithorian/ith_shirt_s09.iff wearable Issued Ithorian Shirt 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 agility_modified=3 -1 31 63 -1 45 0 0 npe clothing
item_ithorian_vest_02_01 object/tangible/wearables/ithorian/ith_vest_s02.iff wearable Issued Ithorian Vest 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 agility_modified=3 -1 0 63 -1 45 0 0 npe clothing
item_jedi_robe_04_01 object/tangible/wearables/robe/robe_s05.iff wearable Cloak of the Kursk 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=50,precision_modified=80 -1 -1 -1 -1 7500 0 0 ToW expansion
item_jedi_robe_04_02 object/tangible/wearables/robe/robe_s05.iff wearable Robes of the Storm Caller 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=50,strength_modified=80 -1 -1 -1 -1 7500 0 0 ToW expansion
item_jedi_robe_04_03 object/tangible/wearables/robe/robe_s05_h1.iff wearable Jedi Knight Cloak 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=80,agility_modified=5,strength_modified=50,precision_modified=50 -1 -1 -1 -1 7500 0 0 ToW expansion
item_jedi_robe_04_04 object/tangible/wearables/robe/robe_s05_h1.iff wearable Jedi Knight Cloak 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=80,agility_modified=5,luck_modified=50,precision_modified=50 -1 -1 -1 -1 7500 0 0 ToW expansion
item_jedi_robe_06_01 object/tangible/wearables/robe/robe_s05_h1.iff wearable Jedi Master Cloak 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=100,strength_modified=100,luck_modified=100,precision_modified=100 -1 -1 -1 -1 7500 0 0 ToW expansion
item_jedi_robe_06_02 object/tangible/wearables/robe/robe_s05_h1.iff wearable Jedi Master Cloak 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=100,strength_modified=100,luck_modified=100,precision_modified=100 -1 -1 -1 -1 7500 0 0 ToW expansion
item_jedi_robe_06_03 object/tangible/wearables/robe/robe_s33_h1.iff wearable Shatterpoint Cloak 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 90 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=135,agility_modified=170,strength_modified=170,luck_modified=170,expertise_damage_weapon_9=4,expertise_damage_weapon_10=4,expertise_damage_weapon_11=4 -1 -1 -1 -1 0 0 0
item_jedi_robe_06_04 object/tangible/wearables/robe/robe_s32_h1.iff wearable Cloak of Hate 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 90 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=135,agility_modified=170,luck_modified=170,precision_modified=170,expertise_damage_line_fs_ae_dm_cc=4 -1 -1 -1 -1 0 0 0
item_jedi_robe_06_05 object/tangible/wearables/robe/robe_s33.iff wearable Shatterpoint Cloak 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 90 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=135,agility_modified=135,strength_modified=135,luck_modified=135,expertise_damage_weapon_9=4,expertise_damage_weapon_10=4,expertise_damage_weapon_11=4 -1 -1 -1 -1 0 0 0
item_jedi_robe_06_06 object/tangible/wearables/robe/robe_s32.iff wearable Cloak of Hate 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 90 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=135,agility_modified=135,luck_modified=135,precision_modified=135,expertise_damage_line_fs_ae_dm_cc=4 -1 -1 -1 -1 0 0 0
item_jedi_robe_dark_03_01 object/tangible/wearables/robe/robe_jedi_dark_s01.iff wearable Acolyte Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=100,precision_modified=100 -1 -1 -1 -1 3500 0 0
item_jedi_robe_dark_03_02 object/tangible/wearables/robe/robe_jedi_dark_s02.iff wearable Apprentice Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=145,precision_modified=145 -1 -1 -1 -1 6000 0 0
item_jedi_robe_dark_03_03 object/tangible/wearables/robe/robe_jedi_dark_s02.iff wearable Jedi Knight Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=185,luck_modified=185,precision_modified=185 -1 -1 -1 -1 7700 0 0
item_jedi_robe_dark_04_01 object/tangible/wearables/robe/robe_jedi_dark_s01.iff wearable Dark Jedi Knight Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 force_sensitive 1 1 1 1 1 0 0 90001 0 0 -1 -1 -1 -1 0 0 0
item_jedi_robe_dark_04_02 object/tangible/wearables/robe/robe_jedi_dark_s02.iff wearable Dark Jedi Enforcer Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 force_sensitive 1 1 1 1 1 0 0 90001 0 0 -1 -1 -1 -1 0 0 0
item_jedi_robe_dark_04_03 object/tangible/wearables/robe/robe_jedi_dark_s03.iff wearable Dark Jedi Templar Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 force_sensitive 1 1 1 1 1 0 0 90001 0 0 -1 -1 -1 -1 0 0 0
item_jedi_robe_dark_04_04 object/tangible/wearables/robe/robe_jedi_dark_s04.iff wearable Elder Jedi Oppressor Robe 1 1000 0 0 0 0 0 0 0 0 0 0 proc_old_dark_jedi_gift 0 0 0 appearance/pt_heal.prt 0 0 0 0 80 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=250,luck_modified=250,precision_modified=250 -1 -1 -1 -1 0 0 0
item_jedi_robe_dark_04_05 object/tangible/wearables/robe/robe_jedi_dark_s05.iff wearable Dark Jedi Council Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 force_sensitive 1 1 1 1 1 0 0 90001 0 0 -1 -1 -1 -1 0 0 0
item_jedi_robe_light_03_01 object/tangible/wearables/robe/robe_jedi_light_s01.iff wearable Acolyte Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=100,strength_modified=100 -1 -1 -1 -1 3500 0 0
item_jedi_robe_light_03_02 object/tangible/wearables/robe/robe_jedi_light_s02.iff wearable Apprentice Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=145,strength_modified=145 -1 -1 -1 -1 6000 0 0
item_jedi_robe_light_03_03 object/tangible/wearables/robe/robe_jedi_light_s02.iff wearable Jedi Knight Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=185,agility_modified=185,strength_modified=185 -1 -1 -1 -1 7700 0 0
item_jedi_robe_light_04_01 object/tangible/wearables/robe/robe_jedi_light_s01.iff wearable Jedi Knight Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 force_sensitive 1 1 1 1 1 0 0 90001 0 0 -1 -1 -1 -1 0 0 0
item_jedi_robe_light_04_02 object/tangible/wearables/robe/robe_jedi_light_s02.iff wearable Jedi Sentinel Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 force_sensitive 1 1 1 1 1 0 0 90001 0 0 -1 -1 -1 -1 0 0 0
item_jedi_robe_light_04_03 object/tangible/wearables/robe/robe_jedi_light_s03.iff wearable Jedi Consular Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 force_sensitive 1 1 1 1 1 0 0 90001 0 0 -1 -1 -1 -1 0 0 0
item_jedi_robe_light_04_04 object/tangible/wearables/robe/robe_jedi_light_s04.iff wearable Elder Jedi Arbiter Robe 1 1000 0 0 0 0 0 0 0 0 0 0 proc_old_light_jedi_gift 0 0 0 appearance/pt_heal.prt 0 0 0 0 80 force_sensitive 1 1 1 1 1 0 0 90001 0 0 constitution_modified=250,agility_modified=250,strength_modified=250 -1 -1 -1 -1 0 0 0
item_jedi_robe_light_04_05 object/tangible/wearables/robe/robe_jedi_light_s05.iff wearable Jedi Council Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 force_sensitive 1 1 1 1 1 0 0 90001 0 0 -1 -1 -1 -1 0 0 0
item_jedi_robe_padawan_04_01 object/tangible/wearables/robe/robe_jedi_padawan_generic.iff wearable Padawan Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 force_sensitive 1 1 1 1 1 0 0 90001 0 0 agility_modified=21 -1 -1 -1 -1 0 0 0
item_lifeday_09_jacket_01 object/tangible/wearables/jacket/jacket_lifeday_09_01.iff wearable Life Day Jacket 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 -1 -1 -1 -1 0 0 0
item_lifeday_09_jacket_02 object/tangible/wearables/jacket/jacket_lifeday_09_02.iff wearable Holiday Jacket 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 -1 -1 -1 -1 0 0 0
item_lifeday_gift_04_13 object/tangible/wearables/necklace/necklace_lifeday.iff wearable Wookiee Life Day Necklace 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 -1 -1 -1 -1 0 0 0
@@ -1151,8 +1124,6 @@ item_npe_bracelet_melee_defense_01_01 object/tangible/wearables/bracelet/bracele
item_npe_bracelet_rng_defense_01_01 object/tangible/wearables/bracelet/bracelet_s06_r.iff wearable Warped Soldier's Bracelet 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 appearance/pt_heal.prt 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 agility_modified=3 -1 -1 -1 -1 200 0 0
item_npe_bracelet_ter_neg_01_01 object/tangible/wearables/bracelet/bracelet_s02_r.iff wearable Warped Traveler's Bracelet 1 1000 0 0 0 0 0 0 0 0 0 0 trivialSlopeMove 0 0 0 appearance/pt_heal.prt 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 -1 -1 -1 -1 200 0 0
item_npe_bracelet_unarmed_damage_01_01 object/tangible/wearables/bracelet/bracelet_s03_r.iff wearable Warped Strongman's Bracer 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 appearance/pt_heal.prt 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 strength_modified=3 -1 -1 -1 -1 200 0 0
item_npe_fs_robe_02_01 object/tangible/wearables/robe/robe_jedi_padawan_generic.iff wearable Padawan Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 force_sensitive 1 1 1 1 1 0 0 0 0 0 agility_modified=10 -1 -1 -1 -1 0 0 0
item_npe_fs_robe_02_02 object/tangible/wearables/robe/robe_jedi_padawan_generic.iff wearable Initiate's Robe 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 force_sensitive 1 1 1 1 1 0 0 0 0 0 constitution_modified=21 -1 -1 -1 -1 1250 0 0
item_npe_hunting_necklace_01_01 object/tangible/wearables/necklace/necklace_s01.iff wearable Hunting Necklace 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 luck_modified=3 -1 -1 -1 -1 250 0 0
item_npe_inaldras_bracelet_01_01 object/tangible/wearables/bracelet/bracelet_s04_r.iff wearable Inaldra's Bracelet 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 agility_modified=3 -1 -1 -1 -1 250 0 0
item_npe_medic_bracelet_01_01 object/tangible/wearables/bracelet/bracelet_s06_r.iff wearable Polis Massan Bracelet 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 stamina_modified=2 -1 -1 -1 -1 250 0 0
@@ -1659,4 +1630,4 @@ item_clothing_wookiee_shoulder_pad_01_02 object/tangible/wearables/wookiee/wke_s
item_clothing_wookiee_skirt_01_01 object/tangible/wearables/wookiee/wke_skirt_s01.iff wearable Decorative Waist Wrap 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 -1 -1 -1 -1 0 0 0
item_clothing_wookiee_skirt_01_02 object/tangible/wearables/wookiee/wke_skirt_s02.iff wearable Sigiled Waist Wrap 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 -1 -1 -1 -1 0 0 0
item_clothing_wookiee_skirt_01_03 object/tangible/wearables/wookiee/wke_skirt_s03.iff wearable Weighted Waist Wrap 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 -1 -1 -1 -1 0 0 0
item_clothing_wookiee_skirt_01_04 object/tangible/wearables/wookiee/wke_skirt_s04.iff wearable Simple Waist Wrap 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 -1 -1 -1 -1 0 0 0
item_clothing_wookiee_skirt_01_04 object/tangible/wearables/wookiee/wke_skirt_s04.iff wearable Simple Waist Wrap 1 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 -1 -1 -1 -1 0 0 0
@@ -1,62 +1,36 @@
/***********************************************************************************
* 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.player.experience.skills;
* along with Holocore. If not, see <http:></http:>//www.gnu.org/licenses/>. *
*/
package com.projectswg.holocore.intents.gameplay.player.experience.skills
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
import me.joshlarson.jlcommon.control.Intent;
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject
import me.joshlarson.jlcommon.control.Intent
public class SkillModIntent extends Intent {
class SkillModIntent(val skillModName: String, val adjustBase: Int, val adjustModifier: Int, vararg val affectedCreatures: CreatureObject) : Intent() {
private final String skillModName;
private final int adjustBase;
private final int adjustModifier;
private final CreatureObject[] affectedCreatures;
public SkillModIntent(String skillModName, int adjustBase, int adjustModifier, CreatureObject... affectedCreatures) {
this.skillModName = skillModName;
this.adjustBase = adjustBase;
this.adjustModifier = adjustModifier;
this.affectedCreatures = affectedCreatures;
}
public int getAdjustModifier() {
return adjustModifier;
}
public int getAdjustBase() {
return adjustBase;
}
public String getSkillModName() {
return skillModName;
}
public CreatureObject[] getAffectedCreatures() {
return affectedCreatures;
}
override fun toString() = "SkillModIntent['$skillModName' base=$adjustBase mod=$adjustModifier creatures=${affectedCreatures.toList()}]"
}
@@ -1,65 +0,0 @@
/***********************************************************************************
* 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.support.objects.swg;
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
import me.joshlarson.jlcommon.control.Intent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ContainerTransferIntent extends Intent {
private SWGObject obj;
private SWGObject container;
private SWGObject oldContainer;
public ContainerTransferIntent(@NotNull SWGObject obj, @Nullable SWGObject oldContainer, @Nullable SWGObject container) {
this.obj = obj;
this.oldContainer = oldContainer;
this.container = container;
}
@NotNull
public SWGObject getObject() {
return obj;
}
@Nullable
public SWGObject getContainer() {
return container;
}
@Nullable
public SWGObject getOldContainer() {
return oldContainer;
}
public static void broadcast(@NotNull SWGObject obj, @Nullable SWGObject oldContainer, @Nullable SWGObject newContainer) {
new ContainerTransferIntent(obj, oldContainer, newContainer).broadcast();
}
}
@@ -0,0 +1,48 @@
/***********************************************************************************
* 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:></http:>//www.gnu.org/licenses/>. *
*/
package com.projectswg.holocore.intents.support.objects.swg
import com.projectswg.holocore.resources.support.objects.swg.SWGObject
import me.joshlarson.jlcommon.control.Intent
class ContainerTransferIntent(val `object`: SWGObject, val oldContainer: SWGObject?, val oldArrangement: Int, val container: SWGObject?, val arrangement: Int) : Intent() {
/** Alias for kotlin code, allowed as a stylistic choice */
val obj: SWGObject
get() = `object`
override fun toString() = "ContainerTransferIntent[obj=$`object` old=$oldArrangement/$oldContainer new=$arrangement/$container]"
companion object {
fun broadcast(obj: SWGObject, oldContainer: SWGObject?, oldArrangement: Int, newContainer: SWGObject?, arrangement: Int) {
ContainerTransferIntent(obj, oldContainer, oldArrangement, newContainer, arrangement).broadcast()
}
}
}
@@ -1,184 +0,0 @@
/***********************************************************************************
* 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.gameplay.crafting.resource.galactic;
import com.projectswg.common.data.location.Terrain;
import com.projectswg.holocore.resources.gameplay.crafting.resource.galactic.storage.GalacticResourceContainer;
import com.projectswg.holocore.resources.gameplay.crafting.resource.raw.RawResource;
import com.projectswg.holocore.resources.support.data.namegen.SWGNameGenerator;
import com.projectswg.holocore.resources.support.data.server_info.StandardLog;
import com.projectswg.holocore.resources.support.data.server_info.mongodb.PswgDatabase;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
import static java.util.stream.Collectors.toList;
public class GalacticResourceSpawner {
private static final Terrain [] ALL_PLANETS = new Terrain[] {
Terrain.CORELLIA, Terrain.DANTOOINE, Terrain.DATHOMIR,
Terrain.ENDOR, Terrain.KASHYYYK_MAIN, Terrain.LOK,
Terrain.NABOO, Terrain.RORI, Terrain.TALUS,
Terrain.TATOOINE, Terrain.YAVIN4, Terrain.MUSTAFAR
};
private static final Terrain [] BASE_PLANETS = new Terrain[] {
Terrain.CORELLIA, Terrain.DANTOOINE, Terrain.DATHOMIR,
Terrain.ENDOR, Terrain.LOK, Terrain.NABOO,
Terrain.RORI, Terrain.TALUS, Terrain.TATOOINE,
Terrain.YAVIN4
};
private final Random random;
private final AtomicLong resourceIdMax;
private final SWGNameGenerator resourceNameGenerator;
public GalacticResourceSpawner() {
this.random = new Random();
this.resourceNameGenerator = new SWGNameGenerator();
this.resourceIdMax = new AtomicLong(0);
}
public void initialize() {
loadResources();
updateAllResources();
}
public void terminate() {
saveResources();
}
public void updateAllResources() {
updateSpawns();
updateUnusedPools();
}
private void loadResources() {
long startTime = StandardLog.onStartLoad("galactic resources");
int resourceCount = 0;
for (GalacticResource resource : PswgDatabase.INSTANCE.getResources().getResources()) {
GalacticResourceContainer.getContainer().addGalacticResource(resource);
if (resource.getId() > resourceIdMax.get())
resourceIdMax.set(resource.getId());
resourceCount++;
}
StandardLog.onEndLoad(resourceCount, "galactic resources", startTime);
}
private void saveResources() {
GalacticResourceLoader loader = new GalacticResourceLoader();
loader.saveResources(GalacticResourceContainer.getContainer().getAllResources());
PswgDatabase.INSTANCE.getResources().setResources(GalacticResourceContainer.getContainer().getAllResources());
}
private void updateUnusedPools() {
List<RawResource> rawResources = GalacticResourceContainer.getContainer().getRawResources();
for (RawResource raw : rawResources) {
if (raw.getMaxPools() == 0)
continue;
updateUnusedResourcePool(raw);
}
}
private void updateUnusedResourcePool(RawResource raw) {
int spawned = GalacticResourceContainer.getContainer().getSpawnedGalacticResources(raw);
int minTypes = raw.getMinTypes();
int maxTypes = raw.getMaxTypes();
if (spawned >= minTypes)
return; // Only respawn once total number spawned in goes below minTypes
int targetTypes = calculateTargetTypes(minTypes, maxTypes);
for (int i = spawned; i < targetTypes; i++) {
createNewResourceWithSpawns(raw);
}
}
private int calculateTargetTypes(int minTypes, int maxTypes) {
double x = random.nextDouble();
return (int) (x * x * (maxTypes - minTypes)) + minTypes;
}
private void createNewResourceWithSpawns(RawResource raw) {
int targetSpawns = random.nextInt(raw.getMaxPools() - raw.getMinPools() + 1) + raw.getMinPools();
GalacticResource resource = createNewResource(raw);
Terrain restricted = getRestrictedResource(raw);
if (restricted == null) {
for (Terrain terrain : BASE_PLANETS) {
for (int i = 0; i < targetSpawns; i++) {
createNewSpawn(resource, terrain);
}
}
} else {
for (int i = 0; i < targetSpawns; i++) {
createNewSpawn(resource, restricted);
}
}
}
private GalacticResource createNewResource(RawResource raw) {
long newId = resourceIdMax.incrementAndGet();
GalacticResource resource;
do {
String newName = resourceNameGenerator.generateName("resources");
resource = new GalacticResource(newId, newName, raw.getId());
resource.setRawResource(raw);
} while (!GalacticResourceContainer.getContainer().addGalacticResource(resource));
return resource;
}
private void createNewSpawn(GalacticResource resource, Terrain terrain) {
GalacticResourceSpawn spawn = new GalacticResourceSpawn(resource.getId());
spawn.setRandomValues(terrain);
resource.addSpawn(spawn);
}
private void updateSpawns() {
List<GalacticResource> resources = GalacticResourceContainer.getContainer().getAllResources();
for (GalacticResource resource : resources) {
List<GalacticResourceSpawn> spawns = resource.getSpawns();
if (spawns.isEmpty())
continue;
List<GalacticResourceSpawn> expired = spawns.stream().filter(GalacticResourceSpawn::isExpired).collect(toList());
expired.forEach(resource::removeSpawn);
}
}
private Terrain getRestrictedResource(RawResource resource) {
String key = resource.getName().getKey();
if (key.length() >= 2 && Character.isDigit(key.charAt(key.length()-1)) && key.charAt(key.length()-2) == '_')
key = key.substring(0, key.lastIndexOf('_'));
for (Terrain test : ALL_PLANETS) {
if (key.endsWith(test.getName()))
return test;
}
if (key.endsWith("kashyyyk")) // special case because kashyyyk = kashyyyk_main
return Terrain.KASHYYYK_MAIN;
return null;
}
}
@@ -0,0 +1,168 @@
/***********************************************************************************
* 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:></http:>//www.gnu.org/licenses/>. *
*/
package com.projectswg.holocore.resources.gameplay.crafting.resource.galactic
import com.projectswg.common.data.location.Terrain
import com.projectswg.holocore.resources.gameplay.crafting.resource.galactic.storage.GalacticResourceContainer
import com.projectswg.holocore.resources.gameplay.crafting.resource.raw.RawResource
import com.projectswg.holocore.resources.support.data.namegen.SWGNameGenerator
import com.projectswg.holocore.resources.support.data.server_info.StandardLog
import com.projectswg.holocore.resources.support.data.server_info.mongodb.PswgDatabase
import me.joshlarson.jlcommon.log.Log
import java.util.concurrent.ThreadLocalRandom
import java.util.concurrent.atomic.AtomicLong
import java.util.function.Consumer
import java.util.stream.Collectors.toList
class GalacticResourceSpawner {
private val resourceIdMax = AtomicLong(0)
private val resourceNameGenerator = SWGNameGenerator()
fun initialize() {
loadResources()
updateAllResources()
}
fun terminate() {
saveResources()
}
fun updateAllResources() {
updateSpawns()
updateUnusedPools()
}
private fun loadResources() {
val startTime = StandardLog.onStartLoad("galactic resources")
var resourceCount = 0
for (resource in PswgDatabase.resources.resources) {
GalacticResourceContainer.addGalacticResource(resource)
if (resource.id > resourceIdMax.get())
resourceIdMax.set(resource.id)
resourceCount++
}
StandardLog.onEndLoad(resourceCount, "galactic resources", startTime)
}
private fun saveResources() {
val loader = GalacticResourceLoader()
loader.saveResources(GalacticResourceContainer.allResources)
PswgDatabase.resources.resources = GalacticResourceContainer.allResources
}
private fun updateUnusedPools() {
val rawResources = GalacticResourceContainer.rawResources
for (raw in rawResources) {
if (raw.maxPools == 0)
continue
updateUnusedResourcePool(raw)
}
}
private fun updateUnusedResourcePool(raw: RawResource) {
val spawned = GalacticResourceContainer.getSpawnedGalacticResources(raw)
val minTypes = raw.minTypes
val maxTypes = raw.maxTypes
if (spawned >= minTypes)
return // Only respawn once total number spawned in goes below minTypes
val targetTypes = calculateTargetTypes(minTypes, maxTypes)
for (i in spawned until targetTypes) {
createNewResourceWithSpawns(raw)
}
}
private fun calculateTargetTypes(minTypes: Int, maxTypes: Int): Int {
val x = ThreadLocalRandom.current().nextDouble()
return (x * x * (maxTypes - minTypes).toDouble()).toInt() + minTypes
}
private fun createNewResourceWithSpawns(raw: RawResource) {
val targetSpawns = ThreadLocalRandom.current().nextInt(raw.minPools, raw.maxPools+1)
val resource = createNewResource(raw)
val restricted = getRestrictedResource(raw)
if (restricted == null) {
for (terrain in BASE_PLANETS) {
for (i in 0 until targetSpawns) {
createNewSpawn(resource, terrain)
}
}
} else {
for (i in 0 until targetSpawns) {
createNewSpawn(resource, restricted)
}
}
}
private fun createNewResource(raw: RawResource): GalacticResource {
val newId = resourceIdMax.incrementAndGet()
var resource: GalacticResource
do {
val newName = resourceNameGenerator.generateName("resources")
resource = GalacticResource(newId, newName, raw.id)
resource.rawResource = raw
Log.t("Generating new resource: $resource $raw")
} while (!GalacticResourceContainer.addGalacticResource(resource))
return resource
}
private fun createNewSpawn(resource: GalacticResource, terrain: Terrain) {
val spawn = GalacticResourceSpawn(resource.id)
spawn.setRandomValues(terrain)
resource.addSpawn(spawn)
}
private fun updateSpawns() {
val resources = GalacticResourceContainer.allResources
for (resource in resources) {
val spawns = resource.spawns
if (spawns.isEmpty())
continue
val expired = spawns.stream().filter { it.isExpired }.collect(toList())
expired.forEach(Consumer<GalacticResourceSpawn> { resource.removeSpawn(it) })
}
}
private fun getRestrictedResource(resource: RawResource): Terrain? {
var key = resource.name.key
if (key.length >= 2 && Character.isDigit(key[key.length - 1]) && key[key.length - 2] == '_')
key = key.substring(0, key.lastIndexOf('_'))
for (test in ALL_PLANETS) {
if (key.endsWith(test.getName()))
return test
}
return if (key.endsWith("kashyyyk")) Terrain.KASHYYYK_MAIN else null
}
companion object {
private val ALL_PLANETS = arrayOf(Terrain.CORELLIA, Terrain.DANTOOINE, Terrain.DATHOMIR, Terrain.ENDOR, Terrain.KASHYYYK_MAIN, Terrain.LOK, Terrain.NABOO, Terrain.RORI, Terrain.TALUS, Terrain.TATOOINE, Terrain.YAVIN4, Terrain.MUSTAFAR)
private val BASE_PLANETS = arrayOf(Terrain.CORELLIA, Terrain.DANTOOINE, Terrain.DATHOMIR, Terrain.ENDOR, Terrain.LOK, Terrain.NABOO, Terrain.RORI, Terrain.TALUS, Terrain.TATOOINE, Terrain.YAVIN4)
}
}
@@ -1,119 +0,0 @@
/***********************************************************************************
* 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.gameplay.crafting.resource.galactic.storage;
import com.projectswg.common.data.location.Terrain;
import com.projectswg.holocore.resources.gameplay.crafting.resource.galactic.GalacticResource;
import com.projectswg.holocore.resources.gameplay.crafting.resource.raw.RawResource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static java.util.stream.Collectors.toList;
public enum GalacticResourceContainer {
INSTANCE;
private final Map<Long, RawResource> rawResources;
private final Map<Long, GalacticResource> galacticResources;
private final Map<String, GalacticResource> galacticResourcesByName;
private final Map<RawResource, List<GalacticResource>> rawToGalactic;
GalacticResourceContainer() {
this.rawResources = new ConcurrentHashMap<>();
this.galacticResources = new ConcurrentHashMap<>();
this.galacticResourcesByName = new ConcurrentHashMap<>();
this.rawToGalactic = new ConcurrentHashMap<>();
}
public RawResource getRawResource(long resourceId) {
return rawResources.get(resourceId);
}
public GalacticResource getGalacticResource(long resourceId) {
return galacticResources.get(resourceId);
}
public GalacticResource getGalacticResourceByName(String resourceName) {
return galacticResourcesByName.get(resourceName);
}
public List<RawResource> getRawResources() {
return copyImmutable(rawResources.values());
}
public List<GalacticResource> getGalacticResources(RawResource rawResource) {
return copyImmutable(rawToGalactic.get(rawResource));
}
public List<GalacticResource> getSpawnedResources(Terrain terrain) {
return galacticResources.values().stream()
.filter(r -> !r.getSpawns(terrain).isEmpty())
.collect(toList());
}
public int getSpawnedGalacticResources(RawResource rawResource) {
return (int) galacticResources.values().stream()
.filter(r -> !r.getSpawns().isEmpty())
.map(r -> r.getRawResourceId() == rawResource.getId())
.count();
}
public void addRawResource(RawResource resource) {
RawResource replaced = rawResources.put(resource.getId(), resource);
assert replaced == null : "raw resource overwritten";
}
public boolean addGalacticResource(GalacticResource resource) {
RawResource raw = getRawResource(resource.getRawResourceId());
Objects.requireNonNull(raw, "Invalid raw resource ID in GalacticResource!");
if (galacticResources.putIfAbsent(resource.getId(), resource) == null) {
if (galacticResourcesByName.putIfAbsent(resource.getName(), resource) == null) {
rawToGalactic.computeIfAbsent(raw, k -> new ArrayList<>()).add(resource);
return true;
} else {
galacticResources.remove(resource.getId());
}
}
return false;
}
public List<GalacticResource> getAllResources() {
return copyImmutable(galacticResources.values());
}
public static GalacticResourceContainer getContainer() {
return INSTANCE;
}
private static <T> List<T> copyImmutable(Collection<T> list) {
if (list == null)
return Collections.unmodifiableList(new ArrayList<>());
return List.copyOf(list);
}
}
@@ -0,0 +1,92 @@
/***********************************************************************************
* 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:></http:>//www.gnu.org/licenses/>. *
*/
package com.projectswg.holocore.resources.gameplay.crafting.resource.galactic.storage
import com.projectswg.common.data.location.Terrain
import com.projectswg.holocore.resources.gameplay.crafting.resource.galactic.GalacticResource
import com.projectswg.holocore.resources.gameplay.crafting.resource.raw.RawResource
import java.lang.NullPointerException
import java.util.*
import java.util.concurrent.ConcurrentHashMap
object GalacticResourceContainer {
val rawResources: List<RawResource>
get() = rawResourceMap.values.toList()
private val rawResourceMap = ConcurrentHashMap<Long, RawResource>()
private val galacticResourceMap = ConcurrentHashMap<Long, GalacticResource>()
private val galacticResourcesByName = ConcurrentHashMap<String, GalacticResource>()
private val rawToGalactic = ConcurrentHashMap<RawResource, MutableList<GalacticResource>>()
val allResources: List<GalacticResource>
get() = galacticResourceMap.values.toList()
fun getRawResource(resourceId: Long): RawResource? {
return rawResourceMap[resourceId]
}
fun getGalacticResource(resourceId: Long): GalacticResource? {
return galacticResourceMap[resourceId]
}
fun getGalacticResourceByName(resourceName: String): GalacticResource? {
return galacticResourcesByName[resourceName]
}
fun getGalacticResources(rawResource: RawResource): List<GalacticResource> {
return rawToGalactic[rawResource]?.toList() ?: ArrayList()
}
fun getSpawnedResources(terrain: Terrain): List<GalacticResource> {
return galacticResourceMap.values.filter { r -> r.getSpawns(terrain).isNotEmpty() }
}
fun getSpawnedGalacticResources(rawResource: RawResource): Int {
return galacticResourceMap.values.count { r -> r.rawResourceId == rawResource.id && r.spawns.isNotEmpty() }
}
fun addRawResource(resource: RawResource) {
val replaced = rawResourceMap.put(resource.id, resource)
assert(replaced == null) { "raw resource overwritten" }
}
fun addGalacticResource(resource: GalacticResource): Boolean {
val raw = getRawResource(resource.rawResourceId) ?: throw NullPointerException("Invalid raw resource ID in GalacticResource")
if (galacticResourceMap.putIfAbsent(resource.id, resource) == null) {
if (galacticResourcesByName.putIfAbsent(resource.name, resource) == null) {
rawToGalactic.computeIfAbsent(raw) { ArrayList() }.add(resource)
return true
} else {
galacticResourceMap.remove(resource.id)
}
}
return false
}
}
@@ -115,6 +115,11 @@ public class RawResource {
return recycled;
}
@Override
public String toString() {
return "RawResource[id="+id+" name="+name+" type="+type+"]";
}
public static RawResourceBuilder builder(long id) {
return new RawResourceBuilder(id);
}
@@ -106,7 +106,7 @@ class StaticItemLoader internal constructor() : DataLoader() {
val armorLevel: String = set.getText("armor_level")
val armorType: ArmorType
val protection: Double = set.getReal("protection")
val protection: Int = set.getInt("protection").toInt()
val requiredFaction: String = set.getText("required_faction")
val requiredLevel: Int = set.getInt("required_level").toInt()
val requiredProfession: String = set.getText("required_profession")
@@ -40,6 +40,7 @@ import com.projectswg.holocore.resources.support.data.server_info.CachedObjectDa
import com.projectswg.holocore.resources.support.data.server_info.ObjectDatabase;
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.swg.player.PlayerObject;
import com.projectswg.holocore.services.support.global.chat.ChatRoomService;
import com.projectswg.holocore.services.support.global.zone.CharacterLookupService.PlayerLookup;
import org.jetbrains.annotations.NotNull;
@@ -327,7 +328,10 @@ public class ChatRoomHandler {
ChatRoomMessage chatRoomMessage = new ChatRoomMessage(sender, room.getId(), message, oob);
for (ChatAvatar member : room.getMembers()) {
Player player = getPlayer(member);
if (player.getPlayerObject().isIgnored(sender.getName()))
if (player == null)
continue;
PlayerObject playerObject = player.getPlayerObject();
if (playerObject != null && playerObject.isIgnored(sender.getName()))
continue;
player.sendPacket(chatRoomMessage);
@@ -13,7 +13,7 @@ public final class CmdRequestCoreSample implements ICmdCallback {
@Override
public void execute(@NotNull Player player, SWGObject target, @NotNull String args) {
GalacticResource resource = GalacticResourceContainer.getContainer().getGalacticResourceByName(args);
GalacticResource resource = GalacticResourceContainer.INSTANCE.getGalacticResourceByName(args);
if (resource == null) {
SystemMessageIntent.broadcastPersonal(player, "@survey:sample_select_type");
return;
@@ -22,7 +22,7 @@ public final class CmdRequestSurvey implements ICmdCallback {
if (!(target instanceof TangibleObject))
return;
GalacticResource resource = GalacticResourceContainer.getContainer().getGalacticResourceByName(args);
GalacticResource resource = GalacticResourceContainer.INSTANCE.getGalacticResourceByName(args);
if (resource == null) {
SystemMessageIntent.broadcastPersonal(player, "Unknown resource: " + args);
return;
@@ -24,7 +24,6 @@ import java.util.concurrent.ThreadLocalRandom
import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.atomic.AtomicReference
import kotlin.math.cos
import kotlin.math.max
import kotlin.math.sin
class NpcCombatMode(obj: AIObject) : NpcMode(obj) {
@@ -70,32 +70,33 @@ object StaticItemCreator {
if (info.requiredProfession.isNotEmpty())
obj.addAttribute("class_required", "@ui_roadmap:title_" + info.requiredProfession)
obj.addAttribute("required_combat_level", info.requiredLevel.toString())
val kineticMax: Int
val energyMax: Int
when (info.armorType) {
StaticItemLoader.ArmorItemInfo.ArmorType.ASSAULT -> {
kineticMax = 7000
energyMax = 5000
kineticMax = info.protection + 1000
energyMax = info.protection - 1000
obj.addAttribute("armor_category", "@obj_attr_n:armor_assault")
}
StaticItemLoader.ArmorItemInfo.ArmorType.BATTLE -> {
kineticMax = 6000
energyMax = 6000
kineticMax = info.protection
energyMax = info.protection
obj.addAttribute("armor_category", "@obj_attr_n:armor_battle")
}
StaticItemLoader.ArmorItemInfo.ArmorType.RECON -> {
kineticMax = 5000
energyMax = 7000
kineticMax = info.protection - 1000
energyMax = info.protection + 1000
obj.addAttribute("armor_category", "@obj_attr_n:armor_reconnaissance")
}
}
obj.addAttribute("cat_armor_standard_protection.kinetic", calculateProtection(kineticMax, info.protection))
obj.addAttribute("cat_armor_standard_protection.energy", calculateProtection(energyMax, info.protection))
obj.addAttribute("cat_armor_special_protection.special_protection_type_heat", calculateProtection(6000, info.protection))
obj.addAttribute("cat_armor_special_protection.special_protection_type_cold", calculateProtection(6000, info.protection))
obj.addAttribute("cat_armor_special_protection.special_protection_type_acid", calculateProtection(6000, info.protection))
obj.addAttribute("cat_armor_special_protection.special_protection_type_electricity", calculateProtection(6000, info.protection))
obj.addAttribute("cat_armor_standard_protection.kinetic", kineticMax.toString())
obj.addAttribute("cat_armor_standard_protection.energy", energyMax.toString())
obj.addAttribute("cat_armor_special_protection.special_protection_type_heat", info.protection.toString())
obj.addAttribute("cat_armor_special_protection.special_protection_type_cold", info.protection.toString())
obj.addAttribute("cat_armor_special_protection.special_protection_type_acid", info.protection.toString())
obj.addAttribute("cat_armor_special_protection.special_protection_type_electricity", info.protection.toString())
applySkillMods(obj, info.skillMods)
applyColors(obj, info.color)
@@ -244,8 +245,4 @@ object StaticItemCreator {
return if (races.isEmpty()) "" else races.substring(0, races.length - 1)
}
private fun calculateProtection(max: Int, protection: Double): String {
return floor(max * protection).toInt().toString()
}
}
@@ -99,7 +99,7 @@ public class SWGObjectRadial implements RadialHandlerInterface {
// We don't use moveToContainer, because that would trigger auto-stacking.
newStack.systemMove(container);
ContainerTransferIntent.broadcast(newStack, null, container);
ContainerTransferIntent.Companion.broadcast(newStack, null, -1, container, newStack.getSlotArrangement());
ObjectCreatedIntent.broadcast(newStack);
} catch (NumberFormatException e) {
@@ -233,17 +233,19 @@ public abstract class SWGObject extends BaselineObject implements Comparable<SWG
*/
public void moveToContainer(@Nullable SWGObject newParent) {
SWGObject oldParent = parent;
int oldArrangement = this.slotArrangement;
if (systemMove(newParent))
broadcast(new ContainerTransferIntent(this, oldParent, newParent));
broadcast(new ContainerTransferIntent(this, oldParent, oldArrangement, newParent, this.slotArrangement));
}
public void moveToSlot(@NotNull SWGObject newParent, String slot, int arrangementId) {
SWGObject oldParent = parent;
int oldArrangement = this.slotArrangement;
if (oldParent != newParent) {
if (oldParent != null)
oldParent.removeObject(this);
newParent.addSlottedObject(this, List.of(slot), arrangementId);
broadcast(new ContainerTransferIntent(this, oldParent, newParent));
broadcast(new ContainerTransferIntent(this, oldParent, oldArrangement, newParent, slotArrangement));
}
}
@@ -42,6 +42,8 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* CREO 4
@@ -50,6 +52,7 @@ import java.util.Set;
class CreatureObjectClientServerNP implements Persistable, MongoPersistable {
private final CreatureObject obj;
private final Lock skillModLock = new ReentrantLock();
/** CREO4-00 */ private float accelPercent = 1;
/** CREO4-01 */ private float accelScale = 1;
@@ -99,19 +102,24 @@ class CreatureObjectClientServerNP implements Persistable, MongoPersistable {
// TODO: Add Bonus Attribute Setters
public void adjustSkillmod(@NotNull String skillModName, int base, int modifier) {
SkillMod skillMod = skillMods.get(skillModName);
if (skillMod == null) {
// They didn't have this SkillMod already.
skillMods.put(skillModName, new SkillMod(base, modifier));
} else {
// They already had this skillmod.
// All we need to do is adjust the base and the modifier and send an update
skillMod.adjustBase(base);
skillMod.adjustModifier(modifier);
skillMods.update(skillModName);
skillModLock.lock();
try {
SkillMod skillMod = skillMods.get(skillModName);
if (skillMod == null) {
// They didn't have this SkillMod already.
skillMods.put(skillModName, new SkillMod(base, modifier));
} else {
// They already had this skillmod.
// All we need to do is adjust the base and the modifier and send an update
skillMod.adjustBase(base);
skillMod.adjustModifier(modifier);
skillMods.update(skillModName);
}
skillMods.sendDeltaMessage(obj);
} finally {
skillModLock.unlock();
}
skillMods.sendDeltaMessage(obj);
}
public int getSkillModValue(@NotNull String skillModName) {
@@ -149,9 +149,9 @@ enum CombatCommandAttack implements CombatCommandHitType {
DamageType damageType = getDamageType(command, weapon); // Will be based on the equipped weapon or the combat command
int rawDamage = calculateWeaponDamage(source, weapon, command) + command.getAddedDamage();
int finalDamage = rawDamage;
info.setRawDamage(rawDamage);
info.setFinalDamage(rawDamage);
info.setDamageType(damageType);
// The armor of the target will mitigate some of the damage
@@ -162,12 +162,13 @@ enum CombatCommandAttack implements CombatCommandHitType {
// End rolls
int targetHealth = target.getHealth();
boolean incapacitate = targetHealth <= finalDamage;
if (incapacitate) {
final int finalDamage;
if (targetHealth <= info.getFinalDamage()) {
finalDamage = targetHealth; // Target took more damage than they had health left. Final damage becomes the amount of remaining health.
RequestCreatureDeathIntent.broadcast(source, target);
} else {
finalDamage = info.getFinalDamage();
target.modifyHealth(-finalDamage);
}
@@ -54,7 +54,7 @@ public class ResourceService extends Service {
public boolean initialize() {
container.loadResources();
for (RawResource rawResource : container.getResources()) {
GalacticResourceContainer.getContainer().addRawResource(rawResource);
GalacticResourceContainer.INSTANCE.addRawResource(rawResource);
}
spawner.initialize();
spawnerUpdater.startWithFixedRate(0, TimeUnit.HOURS.toMillis(3));
@@ -1,214 +0,0 @@
/***********************************************************************************
* 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.services.gameplay.player.experience.skills;
import com.projectswg.holocore.intents.gameplay.player.experience.skills.SkillModIntent;
import com.projectswg.holocore.intents.support.objects.swg.ContainerTransferIntent;
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
import me.joshlarson.jlcommon.control.IntentHandler;
import me.joshlarson.jlcommon.control.Service;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
/**
* Manages protection granted to the player when equipping a Jedi robe or a piece of equipment.
* Also adds additional protection granted by innate armor.
*/
public class ProtectionService extends Service {
private final Map<String, Integer> armorSlotProtectionMap; // Note that the values of this Map add up to 100.0
private final Map<String, Integer> robeProtectionMap;
private static final int ARM_RPOTECTION = 7;
public ProtectionService() {
armorSlotProtectionMap = Map.of( // This map is unmodifiable
"chest2", 37,
"pants1", 21,
"hat", 14,
"bracer_upper_l", ARM_RPOTECTION,
"bracer_upper_r", ARM_RPOTECTION,
"bicep_l", ARM_RPOTECTION,
"bicep_r", ARM_RPOTECTION
);
robeProtectionMap = Map.of( // This map is unmodifiable
"pseudo_1", 1400, // Faint
"pseudo_2", 3000, // Weak
"pseudo_3", 4000, // Lucent
"pseudo_4", 5000, // Luminous
"pseudo_5", 6500 // Radiant
);
}
@Override
public boolean initialize() {
// Sanity check
int armorProtectionPercentage = armorSlotProtectionMap
.values()
.stream()
.mapToInt(Integer::intValue)
.sum();
return super.initialize() && armorProtectionPercentage == 100;
}
@IntentHandler
private void handleContainerTransferIntent(ContainerTransferIntent intent) {
SWGObject item = intent.getObject();
SWGObject newContainer = intent.getContainer();
SWGObject oldContainer = intent.getOldContainer();
if (newContainer == null || oldContainer == null) {
return;
}
if (newContainer instanceof CreatureObject) {
// They equipped something
handleTransfer(item, (CreatureObject) newContainer, true); // newContainer is a character
} else if (oldContainer instanceof CreatureObject) {
// They unequipped something
handleTransfer(item, (CreatureObject) oldContainer, false); // oldContainer is a character
}
}
private void handleTransfer(SWGObject item, CreatureObject container, boolean equip) {
switch (item.getGameObjectType()) {
case GOT_CLOTHING_CLOAK:
handleTransferRobe(item, container, equip);
break;
case GOT_ARMOR_HEAD:
handleTransferArmor(item, "hat", container, equip);
break;
case GOT_ARMOR_BODY:
handleTransferArmor(item, "chest2", container, equip);
break;
case GOT_ARMOR_LEG:
handleTransferArmor(item, "pants1", container, equip);
break;
case GOT_ARMOR_ARM:
// Covers both biceps and both bracers. They all have the same protection weight.
handleTransferArmor(item, "bicep_r", container, equip);
break;
}
}
private void handleTransferArmor(SWGObject armor, String slotName, CreatureObject creature, boolean equip) {
Integer slotProtection = armorSlotProtectionMap.get(slotName);
if (equip) {
// They equipped this piece or armor. Check if they have a jedi robe with protection equipped. If they do, stop here.
Collection<SWGObject> slottedObjects = creature.getSlottedObjects();
for (SWGObject slottedObject : slottedObjects) {
if (slottedObject.hasAttribute("@obj_attr_n:protection_level")) {
// Jedi robe equipped. Don't give them more protection from the piece of equipped armor.
return;
}
}
} else {
// They unequipped this piece of armor. Deduct the protection instead of adding it.
slotProtection = -slotProtection;
}
adjustArmorProtectionType(creature, armor, "kinetic", "cat_armor_standard_protection.kinetic", slotProtection);
adjustArmorProtectionType(creature, armor, "energy", "cat_armor_standard_protection.energy", slotProtection);
adjustArmorProtectionType(creature, armor, "heat", "cat_armor_special_protection.special_protection_type_heat", slotProtection);
adjustArmorProtectionType(creature, armor, "cold", "cat_armor_special_protection.special_protection_type_cold", slotProtection);
adjustArmorProtectionType(creature, armor, "acid", "cat_armor_special_protection.special_protection_type_acid", slotProtection);
adjustArmorProtectionType(creature, armor, "electricity", "cat_armor_special_protection.special_protection_type_electricity", slotProtection);
}
private int getWeightedProtection(SWGObject item, String attribute, Integer slotProtection) {
if (!item.hasAttribute(attribute)) {
return 0;
}
String attributeRaw = item.getAttribute(attribute);
double protection = Double.parseDouble(attributeRaw);
double weighted = protection * slotProtection / 100.0;
return (int) weighted;
}
private void handleTransferRobe(SWGObject robe, CreatureObject creature, boolean equip) {
// Deduct any existing armor protection if the robe is being equipped or add it back if the robe is unequipped
for (String slotName : armorSlotProtectionMap.keySet()) {
SWGObject slottedObject = creature.getSlottedObject(slotName);
if (slottedObject != null) {
handleTransferArmor(slottedObject, slotName, creature, !equip);
}
}
int robeProtection = robeProtection(robe);
if (robeProtection == 0) {
// Robe doesn't offer protection. Do nothing.
return;
}
if (!equip) {
// They unequipped this item. Deduct the protection instead of adding it.
robeProtection *= -1.0;
}
adjustRobeProtectionType(creature, "kinetic", robeProtection);
adjustRobeProtectionType(creature, "energy", robeProtection);
adjustRobeProtectionType(creature, "heat", robeProtection);
adjustRobeProtectionType(creature, "cold", robeProtection);
adjustRobeProtectionType(creature, "acid", robeProtection);
adjustRobeProtectionType(creature, "electricity", robeProtection);
}
private void adjustArmorProtectionType(CreatureObject creature, SWGObject armor, String skillModName, String attribute, Integer slotProtection) {
int protection = getWeightedProtection(armor, attribute, slotProtection);
if (protection != 0)
new SkillModIntent(skillModName, 0, protection, creature).broadcast();
}
private void adjustRobeProtectionType(CreatureObject creature, String skillModName, int robeProtection) {
if (robeProtection != 0)
new SkillModIntent(skillModName, 0, robeProtection, creature).broadcast();
}
private int robeProtection(SWGObject item) {
String protectionLevel = item.getAttribute("@obj_attr_n:protection_level");
if (protectionLevel == null) {
return 0; // This robe does not offer protection
}
String key = protectionLevel.replace("@obj_attr_n:", "");
return robeProtectionMap.getOrDefault(key, 0);
}
}
@@ -0,0 +1,110 @@
/***********************************************************************************
* 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:></http:>//www.gnu.org/licenses/>. *
*/
package com.projectswg.holocore.services.gameplay.player.experience.skills
import com.projectswg.common.data.objects.GameObjectType
import com.projectswg.holocore.intents.gameplay.player.experience.skills.SkillModIntent
import com.projectswg.holocore.intents.support.objects.swg.ContainerTransferIntent
import com.projectswg.holocore.resources.support.objects.swg.SWGObject
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject
import com.projectswg.holocore.resources.support.objects.swg.player.Profession
import me.joshlarson.jlcommon.control.IntentHandler
import me.joshlarson.jlcommon.control.Service
/**
* Manages protection granted to the player when equipping a Jedi robe or a piece of equipment.
* Also adds additional protection granted by innate armor.
*/
class ProtectionService : Service() {
private val attributeLookup = mapOf( // Unmodifiable
"kinetic" to "cat_armor_standard_protection.kinetic",
"energy" to "cat_armor_standard_protection.energy",
"heat" to "cat_armor_special_protection.special_protection_type_heat",
"cold" to "cat_armor_special_protection.special_protection_type_cold",
"acid" to "cat_armor_special_protection.special_protection_type_acid",
"electricity" to "cat_armor_special_protection.special_protection_type_electricity"
)
private val armorSlotProtectionMap = mapOf( // Unmodifiable
"chest2" to 37,
"pants1" to 21,
"hat" to 14,
"bracer_upper_l" to ARM_RPOTECTION,
"bracer_upper_r" to ARM_RPOTECTION,
"bicep_l" to ARM_RPOTECTION,
"bicep_r" to ARM_RPOTECTION
)
init {
assert(armorSlotProtectionMap.values.sum() == 100)
}
@IntentHandler
private fun handleContainerTransferIntent(intent: ContainerTransferIntent) {
val item = intent.obj
val newContainer = intent.container
val oldContainer = intent.oldContainer
if (newContainer is CreatureObject) {
// They equipped something
handleTransfer(item, newContainer, item.arrangement.getOrNull(intent.arrangement-4) ?: EMPTY_LIST, true) // newContainer is a character
} else if (oldContainer is CreatureObject) {
// They unequipped something
handleTransfer(item, oldContainer, item.arrangement.getOrNull(intent.oldArrangement-4) ?: EMPTY_LIST, false) // oldContainer is a character
}
}
private fun handleTransfer(item: SWGObject, creature: CreatureObject, arrangement: List<String>, equip: Boolean) {
val jedi = creature.playerObject?.profession == Profession.FORCE_SENSITIVE
val robe = item.gameObjectType == GameObjectType.GOT_CLOTHING_CLOAK
if (jedi && robe) {
updateProtection(creature, equip) { attribute -> item.calculateProtection(attribute) }
} else if (!jedi && !robe) {
updateProtection(creature, equip) { attribute -> arrangement.sumBy { slot -> item.calculateProtection(attribute, armorSlotProtectionMap[slot] ?: 0) } }
}
}
private inline fun updateProtection(creature: CreatureObject, equip: Boolean, calculateProtection: (attribute: String) -> Int) {
for ((skillModName, attribute) in attributeLookup) {
val protection = calculateProtection(attribute)
SkillModIntent(skillModName, 0, if (equip) protection else -protection, creature).broadcast()
}
}
private fun SWGObject.calculateProtection(attribute: String) = (getAttribute(attribute)?.toIntOrNull() ?: 0)
private fun SWGObject.calculateProtection(attribute: String, slotProtection: Int) = (getAttribute(attribute)?.toIntOrNull() ?: 0) * slotProtection / 100
companion object {
private const val ARM_RPOTECTION = 7
private val EMPTY_LIST = listOf<String>()
}
}
@@ -1,152 +0,0 @@
package com.projectswg.holocore.services.support.npc.ai;
import com.projectswg.common.data.location.Location;
import com.projectswg.holocore.intents.gameplay.combat.CreatureKilledIntent;
import com.projectswg.holocore.intents.support.npc.ai.CompileNpcMovementIntent;
import com.projectswg.holocore.intents.support.npc.ai.StartNpcMovementIntent;
import com.projectswg.holocore.intents.support.npc.ai.StopNpcMovementIntent;
import com.projectswg.holocore.resources.support.npc.ai.NavigationOffset;
import com.projectswg.holocore.resources.support.npc.ai.NavigationPoint;
import com.projectswg.holocore.resources.support.npc.ai.NavigationRouteType;
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
import com.projectswg.holocore.resources.support.objects.swg.custom.AIObject;
import me.joshlarson.jlcommon.concurrency.ScheduledThreadPool;
import me.joshlarson.jlcommon.control.IntentHandler;
import me.joshlarson.jlcommon.control.Service;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class AIMovementService extends Service {
private final Map<AIObject, NavigationRoute> routes;
private final ScheduledThreadPool movementThreads;
public AIMovementService() {
this.routes = new ConcurrentHashMap<>();
this.movementThreads = new ScheduledThreadPool(Runtime.getRuntime().availableProcessors(), "ai-movement-service-%d");
}
@Override
public boolean start() {
movementThreads.start();
movementThreads.executeWithFixedRate(1000, 1000, this::executeRoutes);
return true;
}
@Override
public boolean stop() {
movementThreads.stop();
return movementThreads.awaitTermination(1000);
}
@IntentHandler
private void handleStartNpcMovementIntent(StartNpcMovementIntent snmi) {
AIObject obj = snmi.getObject();
List<NavigationPoint> route = NavigationPoint.from(obj.getParent(), obj.getLocation(), snmi.getParent(), snmi.getDestination(), snmi.getSpeed());
if (route.isEmpty())
routes.remove(obj);
else
routes.put(obj, new NavigationRoute(obj, route, NavigationRouteType.TERMINATE));
}
@IntentHandler
private void handleCompileNpcMovementIntent(CompileNpcMovementIntent snmi) {
AIObject obj = snmi.getObject();
List<NavigationPoint> route = new ArrayList<>(snmi.getPoints().size());
for (NavigationPoint point : snmi.getPoints()) {
appendRoutePoint(route, offsetLocation(point, snmi.getOffset()), snmi.getSpeed());
}
if (route.isEmpty())
routes.remove(obj);
else
routes.put(obj, new NavigationRoute(obj, route, snmi.getType()));
}
@IntentHandler
private void handleStopNpcMovementIntent(StopNpcMovementIntent snmi) {
routes.remove(snmi.getObject());
}
@IntentHandler
private void handleCreatureKilledIntent(CreatureKilledIntent cki) {
CreatureObject corpse = cki.getCorpse();
if (corpse instanceof AIObject)
routes.remove(corpse);
}
private void executeRoutes() {
routes.values().forEach(NavigationRoute::execute);
}
private void appendRoutePoint(List<NavigationPoint> waypoints, NavigationPoint waypoint, double speed) {
NavigationPoint prev = waypoints.isEmpty() ? null : waypoints.get(waypoints.size()-1);
if (waypoint.isNoOperation()) {
waypoints.add(waypoint);
return;
}
if (prev == null) {
waypoints.add(NavigationPoint.at(waypoint.getParent(), waypoint.getLocation(), speed));
} else {
if (prev.getLocation().equals(waypoint.getLocation()) && prev.getParent() == waypoint.getParent())
return;
waypoints.addAll(NavigationPoint.from(prev.getParent(), prev.getLocation(), waypoint.getParent(), waypoint.getLocation(), speed));
}
}
static NavigationPoint offsetLocation(NavigationPoint point, @Nullable NavigationOffset offset) {
if (offset == null)
return point;
return NavigationPoint.at(point.getParent(), offsetLocation(point.getLocation(), offset), point.getSpeed());
}
static Location offsetLocation(Location location, @NotNull NavigationOffset offset) {
double oX = offset.getX();
double oZ = offset.getZ();
double heading = location.getYaw(); // Should be 0 - 360, with 0 representing north and 270 representing east
double angle = Math.toRadians(heading <= 180 ? heading : (heading - 360)) + Math.atan2(oZ, oX);
double distance = Math.sqrt(oZ*oZ + oX*oX);
return Location.builder(location).setX(location.getX() + Math.sin(angle) * distance).setZ(location.getZ() + Math.cos(angle) * distance).build();
}
private static class NavigationRoute {
private final AIObject obj;
private final List<NavigationPoint> route;
private final NavigationRouteType type;
private final AtomicInteger index;
public NavigationRoute(AIObject obj, List<NavigationPoint> route, NavigationRouteType type) {
this.obj = obj;
this.route = route;
this.type = type;
this.index = new AtomicInteger(0);
}
public void execute() {
int index = this.index.getAndIncrement();
if (index >= route.size()) {
switch (type) {
case LOOP:
this.index.set(0);
index = 0;
break;
case TERMINATE:
StopNpcMovementIntent.broadcast(obj);
return;
}
}
assert index < route.size() && index >= 0;
route.get(index).move(obj);
}
}
}
@@ -0,0 +1,136 @@
package com.projectswg.holocore.services.support.npc.ai
import com.projectswg.common.data.location.Location
import com.projectswg.holocore.intents.gameplay.combat.CreatureKilledIntent
import com.projectswg.holocore.intents.support.npc.ai.CompileNpcMovementIntent
import com.projectswg.holocore.intents.support.npc.ai.StartNpcMovementIntent
import com.projectswg.holocore.intents.support.npc.ai.StopNpcMovementIntent
import com.projectswg.holocore.resources.support.npc.ai.NavigationOffset
import com.projectswg.holocore.resources.support.npc.ai.NavigationPoint
import com.projectswg.holocore.resources.support.npc.ai.NavigationRouteType
import com.projectswg.holocore.resources.support.objects.swg.custom.AIObject
import me.joshlarson.jlcommon.concurrency.ScheduledThreadPool
import me.joshlarson.jlcommon.control.IntentHandler
import me.joshlarson.jlcommon.control.Service
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicInteger
import kotlin.math.cos
import kotlin.math.sin
class AIMovementService : Service() {
private val routes = ConcurrentHashMap<AIObject, NavigationRoute>()
private val movementThreads = ScheduledThreadPool(Runtime.getRuntime().availableProcessors(), "ai-movement-service-%d")
override fun start(): Boolean {
movementThreads.start()
movementThreads.executeWithFixedRate(1000, 1000) { this.executeRoutes() }
return true
}
override fun stop(): Boolean {
movementThreads.stop()
return movementThreads.awaitTermination(1000)
}
@IntentHandler
private fun handleStartNpcMovementIntent(snmi: StartNpcMovementIntent) {
val obj = snmi.getObject()
val route = NavigationPoint.from(obj.parent, obj.location, snmi.parent, snmi.destination, snmi.speed)
if (route.isEmpty())
routes.remove(obj)
else
routes[obj] = NavigationRoute(obj, route, NavigationRouteType.TERMINATE)
}
@IntentHandler
private fun handleCompileNpcMovementIntent(snmi: CompileNpcMovementIntent) {
val obj = snmi.getObject()
val route = ArrayList<NavigationPoint>(snmi.points.size)
val waypoints = snmi.points
for ((index, point) in waypoints.withIndex()) {
val next = waypoints.getOrNull(index+1) ?: waypoints.getOrNull(0)
appendRoutePoint(route, offsetLocation(point, if (next == null) 0.0 else point.location.getHeadingTo(next.location), snmi.offset), snmi.speed)
}
if (route.isEmpty())
routes.remove(obj)
else
routes[obj] = NavigationRoute(obj, route, snmi.type)
}
@IntentHandler
private fun handleStopNpcMovementIntent(snmi: StopNpcMovementIntent) {
routes.remove(snmi.getObject())
}
@IntentHandler
private fun handleCreatureKilledIntent(cki: CreatureKilledIntent) {
val corpse = cki.corpse
if (corpse is AIObject)
routes.remove(corpse)
}
private fun executeRoutes() {
routes.values.forEach { it.execute() }
}
private fun appendRoutePoint(waypoints: MutableList<NavigationPoint>, waypoint: NavigationPoint, speed: Double) {
val prev = if (waypoints.isEmpty()) null else waypoints[waypoints.size - 1]
if (waypoint.isNoOperation) {
waypoints.add(waypoint)
return
}
if (prev == null) {
waypoints.add(NavigationPoint.at(waypoint.parent, waypoint.location, speed))
} else {
if (prev.location.equals(waypoint.location) && prev.parent === waypoint.parent)
return
waypoints.addAll(NavigationPoint.from(prev.parent, prev.location, waypoint.parent, waypoint.location, speed))
}
}
private class NavigationRoute(private val obj: AIObject, private val route: List<NavigationPoint>, private val type: NavigationRouteType) {
private val index = AtomicInteger(0)
fun execute() {
var index = this.index.getAndIncrement()
if (index >= route.size) {
when (type) {
NavigationRouteType.LOOP -> {
this.index.set(0)
index = 0
}
NavigationRouteType.TERMINATE -> {
StopNpcMovementIntent.broadcast(obj)
return
}
}
}
assert(index < route.size && index >= 0)
route[index].move(obj)
}
}
companion object {
internal fun offsetLocation(point: NavigationPoint, heading: Double, offset: NavigationOffset?): NavigationPoint {
return if (offset == null) point else NavigationPoint.at(point.parent, offsetLocation(point.location, heading, offset), point.speed)
}
internal fun offsetLocation(location: Location, heading: Double, offset: NavigationOffset): Location {
val oX = offset.x
val oZ = offset.z
val cos = cos(Math.toRadians(heading)) // heading should be 0 - 360, with 0 representing north and 270 representing east
val sin = sin(Math.toRadians(heading))
val nX = oX * cos - oZ * sin
val nZ = oZ * cos + oX * sin
return Location.builder(location).setX(location.x + nX).setZ(location.z + nZ).build()
}
}
}
@@ -45,9 +45,9 @@ public class TestLocation extends TestRunnerNoIntents {
assertEquals(0, origin.getHeadingTo(pointNorth), 1E-7);
assertEquals(0, pointSouth.getHeadingTo(pointNorth), 1E-7);
assertEquals(90, origin.getHeadingTo(pointEast), 1E-7);
assertEquals(270, origin.getHeadingTo(pointEast), 1E-7);
assertEquals(180, origin.getHeadingTo(pointSouth), 1E-7);
assertEquals(270, origin.getHeadingTo(pointWest), 1E-7);
assertEquals(90, origin.getHeadingTo(pointWest), 1E-7);
assertEquals(0, Location.builder(origin).setHeading(0).build().getYaw(), 1E-7);
assertEquals(90, Location.builder(origin).setHeading(90).build().getYaw(), 1E-7);
@@ -0,0 +1,234 @@
/***********************************************************************************
* Copyright (c) 2019 /// 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.services.gameplay.player.experience
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.creature.CreatureObject
import com.projectswg.holocore.resources.support.objects.swg.player.Profession
import com.projectswg.holocore.services.gameplay.player.experience.skills.ProtectionService
import com.projectswg.holocore.services.gameplay.player.experience.skills.skillmod.SkillModService
import com.projectswg.holocore.test.resources.GenericCreatureObject
import com.projectswg.holocore.test.runners.TestRunnerSynchronousIntents
import org.junit.Assert
import org.junit.Before
import org.junit.Test
class TestProtectionService: TestRunnerSynchronousIntents() {
@Before
fun setupServices() {
registerService(ProtectionService())
registerService(SkillModService())
}
@Test
fun testJediRobeEquip() {
val jedi = createCreature(1, Profession.FORCE_SENSITIVE)
val notjedi = createCreature(2, Profession.SMUGGLER)
val armor = ProtectionArmor()
// Nothing equipped yet
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
// Jedi gets protection from robe
armor.simpleRobe.moveToContainer(jedi)
waitForIntents()
assertProtection(jedi)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
// Should remove the protection
armor.simpleRobe.moveToContainer(null)
waitForIntents()
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
// Non-jedi shouldn't get protection
armor.simpleRobe.moveToContainer(notjedi)
waitForIntents()
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
// Nope, not even really nice protection
armor.betterRobe.moveToContainer(notjedi)
Assert.assertNotEquals("simple robe should have moved away", armor.simpleRobe.parent, notjedi)
waitForIntents()
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
// Resetting - no change expected
armor.simpleRobe.moveToContainer(null)
armor.betterRobe.moveToContainer(null)
Assert.assertNull("simple robe should have moved away", armor.simpleRobe.parent)
Assert.assertNull("better robe should have moved away", armor.simpleRobe.parent)
waitForIntents()
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
// Jedi gets protection from robe (same as earlier)
armor.simpleRobe.moveToContainer(jedi)
waitForIntents()
assertProtection(jedi)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
// Jedi gets nice protection
armor.betterRobe.moveToContainer(jedi)
waitForIntents()
assertProtection(jedi, kinetic = 7000, energy = 7000, heat = 7000, cold = 7000, acid = 7000, electricity = 7000)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
// All good things must come to an end eventually
armor.simpleRobe.moveToContainer(null)
armor.betterRobe.moveToContainer(null)
Assert.assertNull("simple robe should have moved away", armor.simpleRobe.parent)
Assert.assertNull("better robe should have moved away", armor.simpleRobe.parent)
waitForIntents()
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
}
@Test
fun testRISEquip() {
val jedi = createCreature(1, Profession.FORCE_SENSITIVE)
val notjedi = createCreature(2, Profession.SMUGGLER)
val armor = ProtectionArmor()
// Nothing equipped yet
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
// Jedi does not get protection from RIS
armor.risArmor.forEach { it.moveToContainer(jedi) }
waitForIntents()
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
// Still no protection
armor.risArmor.forEach { it.moveToContainer(null) }
waitForIntents()
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
// Non-jedi get protection from armor
armor.risArmor.forEach { it.moveToContainer(notjedi) }
waitForIntents()
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi)
// Resetting
armor.simpleRobe.moveToContainer(null)
armor.betterRobe.moveToContainer(null)
armor.risArmor.forEach { it.moveToContainer(null) }
Assert.assertNull("simple robe should have moved away", armor.simpleRobe.parent)
Assert.assertNull("better robe should have moved away", armor.simpleRobe.parent)
armor.risArmor.forEach { Assert.assertNull("RIS armor should have moved away", it.parent) }
waitForIntents()
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
// Non-jedi don't get protection from robes
armor.simpleRobe.moveToContainer(notjedi)
waitForIntents()
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
// But they do from armor
armor.risArmor.forEach { it.moveToContainer(notjedi) }
waitForIntents()
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi)
// The robe should remove everything but the helmet
armor.simpleRobe.moveToContainer(notjedi)
waitForIntents()
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi, kinetic = 6000*14/100, energy = 6000*14/100, heat = 6000*14/100, cold = 6000*14/100, acid = 6000*14/100, electricity = 6000*14/100)
// All good things must come to an end eventually
armor.simpleRobe.moveToContainer(null)
armor.betterRobe.moveToContainer(null)
armor.risArmor.forEach { it.moveToContainer(null) }
Assert.assertNull("simple robe should have moved away", armor.simpleRobe.parent)
Assert.assertNull("better robe should have moved away", armor.simpleRobe.parent)
armor.risArmor.forEach { Assert.assertNull("RIS armor should have moved away", it.parent) }
waitForIntents()
assertProtection(jedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
assertProtection(notjedi, kinetic = 0, energy = 0, heat = 0, cold = 0, acid = 0, electricity = 0)
}
private fun assertProtection(creature: CreatureObject, kinetic: Int = 6000, energy: Int = 6000, heat: Int = 6000, cold: Int = 6000, acid: Int = 6000, electricity: Int = 6000) {
Assert.assertEquals("kinetic", kinetic, creature.getSkillModValue("kinetic"))
Assert.assertEquals("energy", kinetic, creature.getSkillModValue("energy"))
Assert.assertEquals("heat", kinetic, creature.getSkillModValue("heat"))
Assert.assertEquals("cold", kinetic, creature.getSkillModValue("cold"))
Assert.assertEquals("acid", kinetic, creature.getSkillModValue("acid"))
Assert.assertEquals("electricity", kinetic, creature.getSkillModValue("electricity"))
}
data class ProtectionArmor(val simpleRobe: SWGObject = createSimpleRobe(), val betterRobe: SWGObject = createBetterRobe(), val risArmor: List<SWGObject> = createArmorSetRIS())
companion object {
private fun createCreature(id: Long, profession: Profession): GenericCreatureObject {
val creature = GenericCreatureObject(id)
creature.playerObject.profession = profession
return creature;
}
private fun createSimpleRobe() = createProtectedItem("object/tangible/wearables/robe/robe_jedi_light_s01.iff")
private fun createBetterRobe() = createProtectedItem("object/tangible/wearables/robe/robe_jedi_dark_s01.iff", kinetic = 7000, energy = 7000, heat = 7000, cold = 7000, acid = 7000, electricity = 7000)
private fun createArmorSetRIS(): List<SWGObject> {
return listOf(
createProtectedItem("object/tangible/wearables/armor/ris/armor_ris_boots.iff"),
createProtectedItem("object/tangible/wearables/armor/ris/armor_ris_leggings.iff"),
createProtectedItem("object/tangible/wearables/armor/ris/armor_ris_chest_plate.iff"),
createProtectedItem("object/tangible/wearables/armor/ris/armor_ris_helmet.iff"),
createProtectedItem("object/tangible/wearables/armor/ris/armor_ris_bicep_l.iff"),
createProtectedItem("object/tangible/wearables/armor/ris/armor_ris_bicep_r.iff"),
createProtectedItem("object/tangible/wearables/armor/ris/armor_ris_bracer_l.iff"),
createProtectedItem("object/tangible/wearables/armor/ris/armor_ris_bracer_r.iff"),
createProtectedItem("object/tangible/wearables/armor/ris/armor_ris_gloves.iff")
)
}
private fun createProtectedItem(template: String, kinetic: Int = 6000, energy: Int = 6000, heat: Int = 6000, cold: Int = 6000, acid: Int = 6000, electricity: Int = 6000): SWGObject {
val obj = ObjectCreator.createObjectFromTemplate(template)
obj.addAttribute("cat_armor_standard_protection.kinetic", kinetic.toString())
obj.addAttribute("cat_armor_standard_protection.energy", energy.toString())
obj.addAttribute("cat_armor_special_protection.special_protection_type_heat", heat.toString())
obj.addAttribute("cat_armor_special_protection.special_protection_type_cold", cold.toString())
obj.addAttribute("cat_armor_special_protection.special_protection_type_acid", acid.toString())
obj.addAttribute("cat_armor_special_protection.special_protection_type_electricity", electricity.toString())
return obj;
}
}
}
@@ -29,21 +29,37 @@ package com.projectswg.holocore.services.support.npc.ai
import com.projectswg.common.data.location.Location
import com.projectswg.holocore.resources.support.npc.ai.NavigationOffset
import com.projectswg.holocore.test.runners.TestRunnerNoIntents
import org.junit.Assert
import org.junit.Test
import kotlin.math.sqrt
class TestAIMovementService {
class TestAIMovementService: TestRunnerNoIntents() {
@Test
fun testOffsetLocation() {
testOffset( 1.0, 1.0, 0.0, 1.0, 1.0)
testOffset(-1.0, 1.0, 90.0, 1.0, 1.0)
testOffset(-1.0, -1.0, 180.0, 1.0, 1.0)
testOffset( 1.0, -1.0, 270.0, 1.0, 1.0)
Assert.assertEquals("NORTH", 0.0, headingTo(0.0, 1.0), 1E-7)
Assert.assertEquals("EAST", 270.0, headingTo(1.0, 0.0), 1E-7)
Assert.assertEquals("SOUTH", 180.0, headingTo(0.0, -1.0), 1E-7)
Assert.assertEquals("WEST", 90.0, headingTo(-1.0, 0.0), 1E-7)
testOffset(headingTo(0.0, 1.0), 1.0, 1.0)
testOffset(headingTo(-1.0, 0.0), -1.0, 1.0)
testOffset(headingTo(0.0, -1.0), -1.0, -1.0)
testOffset(headingTo(1.0, 0.0), 1.0, -1.0)
testOffset(headingTo(1.0, 1.0), sqrt(2.0), 0.0)
}
private fun testOffset(x: Double, z: Double, heading: Double, tx: Double, tz: Double) {
val startLocation = Location.builder().setPosition(0.0, 0.0, 0.0).setHeading(heading).build()
AIMovementService.offsetLocation(startLocation, NavigationOffset(tx, tz))
private fun headingTo(eX: Double, eZ: Double): Double {
return Location.builder().setPosition(0.0, 0.0, 0.0).build().getHeadingTo(Location.builder().setPosition(eX, 0.0, eZ).build())
}
private fun testOffset(heading: Double, tx: Double, tz: Double) {
val startLocation = Location.builder().setPosition(0.0, 0.0, 0.0).build()
val endLocation = AIMovementService.offsetLocation(startLocation, heading, NavigationOffset(1.0, 1.0))
Assert.assertEquals("X", tx, endLocation.x, 1E-7)
Assert.assertEquals("Z", tz, endLocation.z, 1E-7)
}
}
@@ -80,8 +80,16 @@ public abstract class TestRunnerSynchronousIntents extends TestRunner {
boolean uninterrupted = Delay.sleepMicro(10);
assert uninterrupted;
}
waitForIntents();
}
protected final void waitForIntents() {
while (intentManager.getIntentCount() > 0) {
boolean uninterrupted = Delay.sleepMicro(10);
boolean uninterrupted = Delay.sleepMilli(1);
assert uninterrupted;
}
while (intentManager.getIntentCount() > 0) {
boolean uninterrupted = Delay.sleepMilli(10);
assert uninterrupted;
}
}
@@ -0,0 +1,60 @@
/***********************************************************************************
* Copyright (c) 2019 /// 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:></http:>//www.gnu.org/licenses/>. *
*/
package com.projectswg.utility.clientdata
import com.projectswg.common.data.swgiff.parsers.SWGParser
import com.projectswg.common.data.swgiff.parsers.terrain.TerrainDataParser
import com.projectswg.holocore.utilities.SdbGenerator
import me.joshlarson.jlcommon.log.Log
import me.joshlarson.jlcommon.log.log_wrapper.ConsoleLogWrapper
import java.io.File
import java.io.IOException
import java.util.*
internal class ConvertTerrain : Converter {
override fun convert() {
println("Converting terrains...")
Log.addWrapper(ConsoleLogWrapper())
try {
SdbGenerator(File("serverdata/terrain/terrains.sdb")).use { sdb ->
sdb.writeColumnNames("slotName", "global", "modifiable", "observeWithParent", "exposeToWorld")
convertFile(sdb, File("clientdata/terrain/tatooine.trn"))
}
} catch (e: IOException) {
e.printStackTrace()
}
}
@Throws(IOException::class)
override fun convertFile(sdb: SdbGenerator, file: File) {
val clientdata = SWGParser.parse(file) as TerrainDataParser
Objects.requireNonNull(clientdata, "Failed to load clientdata")
}
}
@@ -11,6 +11,7 @@ public enum Converters {
ABSTRACT_SLOT_DEFINITION (ConvertSlotDefinition::new),
ABSTRACT_SLOT_DESCRIPTORS (ConvertSlotDescriptor::new),
ABSTRACT_SLOT_ARRANGEMENT (ConvertSlotArrangement::new),
TERRAINS (ConvertTerrain::new),
PROFESSION_TEMPLATES (ConvertProfessionTemplates::new);
private final Supplier<Converter> converter;