Added expertise and skill loaders

This commit is contained in:
Obique
2019-02-05 18:56:33 -06:00
parent a6e08ac08f
commit 42742a3f8d
21 changed files with 5350 additions and 242 deletions

3
.gitignore vendored
View File

@@ -1,8 +1,10 @@
.settings
scripts/
# IDE-based
Holocore.iml
out
classes/
.idea
.classpath
.project
@@ -10,6 +12,7 @@ out
# Gradle
build
.gradle
gradle.properties
# Holocore
/clientdata/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
expertise_tree_id expertise_tree_string_id ui_background_id
INTEGER STRING STRING
1 expertise_tree_bh_general left
2 expertise_tree_bh_path left_bounty_hunter
3 expertise_tree_bh_warfare
4 expertise_tree_fs_general left
5 expertise_tree_fs_path left_jedi
6 expertise_tree_fs_warfare
7 expertise_tree_sm_general left
8 expertise_tree_sm_path left_smuggler
9 expertise_tree_sm_warfare
10 expertise_tree_of_general left
11 expertise_tree_of_path left_officer
12 expertise_tree_of_warfare
13 expertise_tree_co_path left_commando
14 expertise_tree_co_general left
15 expertise_tree_co_warfare
16 expertise_tree_me_general left
17 expertise_tree_me_path left_medic
18 expertise_tree_me_warfare
19 expertise_tree_sp_general left
20 expertise_tree_sp_path left_spy
21 expertise_tree_sp_warfare
22 expertise_tree_en_general left
23 expertise_tree_en_path left_entertainer
24 expertise_tree_en_warfare
25 expertise_tree_trader_domestic left_trader
26 expertise_tree_trader_structure left_trader
27 expertise_tree_trader_munition left_trader
28 expertise_tree_trader_engineer left_trader
29 expertise_tree_trader_general left
30 expertise_tree_beastmaster left_beastmaster
99 expertise_tree_test

View File

@@ -0,0 +1,92 @@
level xp_required xp_type xp_multiplier health_granted expertise_points
INTEGER INTEGER STRING INTEGER INTEGER INTEGER
1 0 combat_meleespecialize_unarmed 1 0 0
2 500 combat_meleespecialize_onehand 1 50 0
3 1700 combat_meleespecialize_twohand 1 75 0
4 3800 combat_meleespecialize_polearm 1 100 0
5 6900 combat_rangedspecialize_rifle 1 125 0
6 11000 combat_rangedspecialize_pistol 1 150 0
7 16200 combat_rangedspecialize_carbine 1 175 0
8 22600 combat_rangedspecialize_heavy 1 200 0
9 30300 bountyhunter 35 225 0
10 39400 jedi_general 1 250 5
11 50000 crafting_medicine_general 1 275 0
12 62200 combat_general 1 300 6
13 76000 medical 1 325 0
14 91500 creaturehandler 1 350 7
15 108800 trapping 1 375 0
16 128000 scout 1 390 8
17 149200 entertainer 1 405 0
18 172500 crafting 1 420 9
19 198000 0 435 0
20 225800 0 450 10
21 256000 0 465 0
22 288700 0 480 11
23 324000 0 495 0
24 362000 0 510 12
25 402800 0 525 0
26 446500 0 540 13
27 493200 0 555 0
28 543000 0 570 14
29 596000 0 585 0
30 652300 0 600 15
31 712100 0 615 0
32 775500 0 630 16
33 842600 0 645 0
34 913600 0 660 17
35 988600 0 675 0
36 1067800 0 690 18
37 1151300 0 705 0
38 1239300 0 720 19
39 1331900 0 735 0
40 1429300 0 750 20
41 1531600 0 765 0
42 1639000 0 780 21
43 1751700 0 795 0
44 1869900 0 810 22
45 1993800 0 825 0
46 2123600 0 840 23
47 2259500 0 855 0
48 2401700 0 870 24
49 2550400 0 885 0
50 2705800 0 900 25
51 2868100 0 915 0
52 3037600 0 930 26
53 3214500 0 945 0
54 3399000 0 960 27
55 3591400 0 1000 0
56 3792000 0 1040 28
57 4001000 0 1080 0
58 4218700 0 1120 29
59 4445400 0 1160 0
60 4681400 0 1200 30
61 4927000 0 1240 0
62 5182500 0 1280 31
63 5448300 0 1320 0
64 5724700 0 1360 32
65 6012100 0 1400 0
66 6310800 0 1440 33
67 6621200 0 1480 0
68 6943700 0 1520 34
69 7278700 0 1560 0
70 7626600 0 1600 35
71 7987800 0 1640 0
72 8362800 0 1680 36
73 8752000 0 1720 0
74 9155900 0 1760 37
75 9575000 0 1800 0
76 10009800 0 1840 38
77 10460800 0 1880 0
78 10928500 0 1920 39
79 11413500 0 1960 0
80 11916400 0 2000 40
81 12437700 0 2000 0
82 12978100 0 2000 41
83 13538200 0 2000 0
84 14118600 0 2000 42
85 14720000 0 2000 0
86 15343100 0 2000 43
87 15988600 0 2000 0
88 16657200 0 2000 44
89 17349700 0 2000 0
90 18066900 0 2000 45

2793
serverdata/skill/skills.sdb Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,66 @@
/***********************************************************************************
* 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.intents.gameplay.player.experience.expertise;
import com.projectswg.holocore.resources.support.data.server_info.loader.ExpertiseLoader.ExpertiseInfo;
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
import me.joshlarson.jlcommon.control.Intent;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class RequestExpertiseIntent extends Intent {
private final @NotNull CreatureObject creature;
private final @NotNull List<@NotNull ExpertiseInfo> expertise;
public RequestExpertiseIntent(@NotNull CreatureObject creature, @NotNull List<@NotNull ExpertiseInfo> expertise) {
this.creature = creature;
this.expertise = Collections.unmodifiableList(expertise);
}
@NotNull
public CreatureObject getCreature() {
return creature;
}
@NotNull
public List<@NotNull ExpertiseInfo> getExpertise() {
return expertise;
}
public static void broadcast(@NotNull CreatureObject creature, @NotNull List<@NotNull ExpertiseInfo> expertise) {
new RequestExpertiseIntent(creature, expertise).broadcast();
}
public static void broadcast(@NotNull CreatureObject creature, @NotNull ExpertiseInfo expertise) {
new RequestExpertiseIntent(creature, List.of(expertise)).broadcast();
}
}

View File

@@ -8,7 +8,13 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
enum CachedLoader {
// Player
BUFFS (BuffLoader::new),
EXPERTISE (ExpertiseLoader::new),
EXPERTISE_TREES (ExpertiseTreeLoader::new),
SKILLS (SkillLoader::new),
PLAYER_LEVELS (PlayerLevelLoader::new),
// Other
BUILDING_CELLS (BuildingCellLoader::new),
NPC_LOADER (NpcLoader::new),
NPC_COMBAT_PROFILES (NpcCombatProfileLoader::new),

View File

@@ -0,0 +1,128 @@
/***********************************************************************************
* 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.resources.support.data.server_info.loader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet;
import java.io.File;
import java.io.IOException;
public final class CollectionLoader extends DataLoader {
CollectionLoader() {
}
@Override
public final void load() throws IOException {
try (SdbResultSet set = SdbLoader.load(new File("serverdata/collection/collection.sdb"))) {
while (set.next()) {
CollectionInfo collection = new CollectionInfo(set);
// TODO: Store information
}
}
}
public static class CollectionInfo {
private final String bookName;
private final String pageName;
private final String collectionName;
private final String slotName;
private final int beginSlotId;
private final int endSlotId;
private final int maxSlotValue;
private final String category1;
private final String category2;
private final String category3;
private final String category4;
private final String category5;
private final String category6;
private final String category7;
private final String category8;
private final String category9;
private final String category10;
private final String category11;
private final String prereqSlotName1;
private final String prereqSlotName2;
private final String prereqSlotName3;
private final String prereqSlotName4;
private final String prereqSlotName5;
private final String icon;
private final String music;
private final String showIfNotYetEarned;
private final boolean hidden;
private final boolean title;
private final String alternateTitle1;
private final String alternateTitle2;
private final String alternateTitle3;
private final String alternateTitle4;
private final String alternateTitle5;
private final boolean noReward;
private final boolean trackServerFirst;
public CollectionInfo(SdbResultSet set) {
this.bookName = set.getText("book_name");
this.pageName = set.getText("page_name");
this.collectionName = set.getText("collection_name");
this.slotName = set.getText("slot_name");
this.beginSlotId = (int) set.getInt("begin_slot_id");
this.endSlotId = (int) set.getInt("end_slot_id");
this.maxSlotValue = (int) set.getInt("max_slot_value");
this.category1 = set.getText("category1");
this.category2 = set.getText("category2");
this.category3 = set.getText("category3");
this.category4 = set.getText("category4");
this.category5 = set.getText("category5");
this.category6 = set.getText("category6");
this.category7 = set.getText("category7");
this.category8 = set.getText("category8");
this.category9 = set.getText("category9");
this.category10 = set.getText("category10");
this.category11 = set.getText("category11");
this.prereqSlotName1 = set.getText("prereq_slot_name1");
this.prereqSlotName2 = set.getText("prereq_slot_name2");
this.prereqSlotName3 = set.getText("prereq_slot_name3");
this.prereqSlotName4 = set.getText("prereq_slot_name4");
this.prereqSlotName5 = set.getText("prereq_slot_name5");
this.icon = set.getText("icon");
this.music = set.getText("music");
this.showIfNotYetEarned = set.getText("show_if_not_yet_earned");
this.hidden = set.getBoolean("hidden");
this.title = set.getBoolean("title");
this.alternateTitle1 = set.getText("alternate_title1");
this.alternateTitle2 = set.getText("alternate_title2");
this.alternateTitle3 = set.getText("alternate_title3");
this.alternateTitle4 = set.getText("alternate_title4");
this.alternateTitle5 = set.getText("alternate_title5");
this.noReward = set.getBoolean("no_reward");
this.trackServerFirst = set.getBoolean("track_server_first");
}
}
}

View File

@@ -22,6 +22,22 @@ public abstract class DataLoader {
return (BuffLoader) CachedLoader.BUFFS.load();
}
public static ExpertiseLoader expertise() {
return (ExpertiseLoader) CachedLoader.EXPERTISE.load();
}
public static ExpertiseTreeLoader expertiseTrees() {
return (ExpertiseTreeLoader) CachedLoader.EXPERTISE_TREES.load();
}
public static SkillLoader skills() {
return (SkillLoader) CachedLoader.SKILLS.load();
}
public static PlayerLevelLoader playerLevels() {
return (PlayerLevelLoader) CachedLoader.PLAYER_LEVELS.load();
}
public static BuildoutLoader buildouts() {
return BuildoutLoader.load(List.of());
}

View File

@@ -0,0 +1,149 @@
/***********************************************************************************
* 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.resources.support.data.server_info.loader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet;
import com.projectswg.holocore.resources.support.data.server_info.loader.ExpertiseTreeLoader.ExpertiseTreeInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.*;
public final class ExpertiseLoader extends DataLoader {
private final Map<String, ExpertiseInfo> expertiseByName;
private final Map<ExpertiseTreeInfo, List<ExpertiseInfo>> expertiseByTree;
ExpertiseLoader() {
this.expertiseByName = new HashMap<>();
this.expertiseByTree = new HashMap<>();
}
@Nullable
public ExpertiseInfo getByName(String name) {
return expertiseByName.get(name);
}
@NotNull
public Collection<ExpertiseInfo> getPeerExpertise(@NotNull ExpertiseInfo expertise) {
Collection<ExpertiseInfo> ret = expertiseByTree.get(expertise.getTree());
return ret == null ? List.of() : Collections.unmodifiableCollection(ret);
}
@NotNull
public Collection<ExpertiseInfo> getExpertiseByTree(ExpertiseTreeInfo tree) {
Collection<ExpertiseInfo> ret = expertiseByTree.get(tree);
return ret == null ? List.of() : Collections.unmodifiableCollection(ret);
}
@NotNull
public Collection<ExpertiseInfo> getAllExpertise() {
return Collections.unmodifiableCollection(expertiseByName.values());
}
@Override
public final void load() throws IOException {
ExpertiseTreeLoader trees = DataLoader.expertiseTrees();
try (SdbResultSet set = SdbLoader.load(new File("serverdata/expertise/expertise.sdb"))) {
while (set.next()) {
ExpertiseInfo expertise = new ExpertiseInfo(set, trees);
expertiseByName.put(expertise.getName(), expertise);
expertiseByTree.computeIfAbsent(expertise.getTree(), t -> new ArrayList<>()).add(expertise);
}
}
}
public static class ExpertiseInfo {
private final String name;
private final ExpertiseTreeInfo tree;
private final int tier;
private final int grid;
private final int rank;
private final int requiredLevel;
private final String requiredFaction;
private final String requiredProfession;
public ExpertiseInfo(SdbResultSet set, ExpertiseTreeLoader trees) {
this.name = set.getText("name");
this.tree = trees.getTreeFromId((int) set.getInt("tree"));
this.tier = (int) set.getInt("tier");
this.grid = (int) set.getInt("grid");
this.rank = (int) set.getInt("rank");
this.requiredLevel = (int) set.getInt("prereq_level");
this.requiredFaction = set.getText("prereq_faction");
this.requiredProfession = formatProfession(set.getText("req_prof"));
}
public String getName() {
return name;
}
public ExpertiseTreeInfo getTree() {
return tree;
}
public int getTier() {
return tier;
}
public int getGrid() {
return grid;
}
public int getRank() {
return rank;
}
public int getRequiredLevel() {
return requiredLevel;
}
public String getRequiredFaction() {
return requiredFaction;
}
public String getRequiredProfession() {
return requiredProfession;
}
private static String formatProfession(String profession) {
switch (profession) {
case "trader_dom": return "trader_0a";
case "trader_struct": return "trader_0b";
case "trader_mun": return "trader_0c";
case "trader_eng": return "trader_0d";
default: return profession + "_1a";
}
}
}
}

View File

@@ -0,0 +1,87 @@
/***********************************************************************************
* 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.resources.support.data.server_info.loader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public final class ExpertiseTreeLoader extends DataLoader {
private final Map<Integer, ExpertiseTreeInfo> trees;
ExpertiseTreeLoader() {
this.trees = new HashMap<>();
}
@Nullable
public ExpertiseTreeInfo getTreeFromId(int id) {
return trees.get(id);
}
@Override
public final void load() throws IOException {
try (SdbResultSet set = SdbLoader.load(new File("serverdata/expertise/expertise_trees.sdb"))) {
while (set.next()) {
ExpertiseTreeInfo treeInfo = new ExpertiseTreeInfo(set);
trees.put(treeInfo.getId(), treeInfo);
}
}
}
public static class ExpertiseTreeInfo {
private final int id;
private final String stringId;
private final String uiBackgroundId;
public ExpertiseTreeInfo(SdbResultSet set) {
this.id = (int) set.getInt("expertise_tree_id");
this.stringId = set.getText("expertise_tree_string_id");
this.uiBackgroundId = set.getText("ui_background_id");
}
public int getId() {
return id;
}
public String getStringId() {
return stringId;
}
public String getUiBackgroundId() {
return uiBackgroundId;
}
}
}

View File

@@ -0,0 +1,72 @@
/***********************************************************************************
* 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.resources.support.data.server_info.loader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet;
import java.io.File;
import java.io.IOException;
public final class PlanetMapLoader extends DataLoader {
PlanetMapLoader() {
}
@Override
public final void load() throws IOException {
try (SdbResultSet set = SdbLoader.load(new File("serverdata/player/planet_map_cat.sdb"))) {
while (set.next()) {
PlanetMapInfo mapInfo = new PlanetMapInfo(set);
// TODO: Store information
}
}
}
public static class PlanetMapInfo {
private final String name;
private final int index;
private final boolean category;
private final boolean subcategory;
private final boolean canBeActive;
private final String faction;
private final boolean factionVisibleOnly;
public PlanetMapInfo(SdbResultSet set) {
this.name = set.getText("name");
this.index = (int) set.getInt("index");
this.category = set.getBoolean("iscategory");
this.subcategory = set.getBoolean("issubcategory");
this.canBeActive = set.getBoolean("can_be_active");
this.faction = set.getText("faction");
this.factionVisibleOnly = set.getBoolean("faction_visible_only");
}
}
}

View File

@@ -0,0 +1,105 @@
/***********************************************************************************
* 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.resources.support.data.server_info.loader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public final class PlayerLevelLoader extends DataLoader {
private final Map<Integer, PlayerLevelInfo> levels;
PlayerLevelLoader() {
this.levels = new HashMap<>();
}
@Nullable
public PlayerLevelInfo getFromLevel(int level) {
return levels.get(level);
}
@Override
public final void load() throws IOException {
try (SdbResultSet set = SdbLoader.load(new File("serverdata/player/player_level.sdb"))) {
while (set.next()) {
PlayerLevelInfo levelInfo = new PlayerLevelInfo(set);
levels.put(levelInfo.getLevel(), levelInfo);
}
}
}
public static class PlayerLevelInfo {
private final int level;
private final int xpRequired;
private final String xpType;
private final int xpMultiplier;
private final int healthGranted;
private final int expertisePoints;
public PlayerLevelInfo(SdbResultSet set) {
this.level = (int) set.getInt("level");
this.xpRequired = (int) set.getInt("xp_required");
this.xpType = set.getText("xp_type");
this.xpMultiplier = (int) set.getInt("xp_multiplier");
this.healthGranted = (int) set.getInt("health_granted");
this.expertisePoints = (int) set.getInt("expertise_points");
}
public int getLevel() {
return level;
}
public int getXpRequired() {
return xpRequired;
}
public String getXpType() {
return xpType;
}
public int getXpMultiplier() {
return xpMultiplier;
}
public int getHealthGranted() {
return healthGranted;
}
public int getExpertisePoints() {
return expertisePoints;
}
}
}

View File

@@ -0,0 +1,64 @@
/***********************************************************************************
* 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.resources.support.data.server_info.loader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet;
import java.io.File;
import java.io.IOException;
public final class PlayerRoleLoader extends DataLoader {
PlayerRoleLoader() {
}
@Override
public final void load() throws IOException {
try (SdbResultSet set = SdbLoader.load(new File("serverdata/player/role.sdb"))) {
while (set.next()) {
RoleInfo role = new RoleInfo(set);
// TODO: Store information
}
}
}
public static class RoleInfo {
private final int index;
private final String roleIcon;
private final String qualifyingSkill;
public RoleInfo(SdbResultSet set) {
this.index = (int) set.getInt("index");
this.roleIcon = set.getText("role_icon");
this.qualifyingSkill = set.getText("qualifying_skill");
}
}
}

View File

@@ -0,0 +1,72 @@
/***********************************************************************************
* 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.resources.support.data.server_info.loader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet;
import java.io.File;
import java.io.IOException;
public final class RoadmapRewardLoader extends DataLoader {
RoadmapRewardLoader() {
}
@Override
public final void load() throws IOException {
try (SdbResultSet set = SdbLoader.load(new File("serverdata/roadmap/item_rewards.sdb"))) {
while (set.next()) {
RoadmapRewardInfo rewardInfo = new RoadmapRewardInfo(set);
// TODO: Store information
}
}
}
public static class RoadmapRewardInfo {
private final String roadmapTemplateName;
private final String roadmapSkillName;
private final String appearanceName;
private final String stringId;
private final String itemDefault;
private final String itemWookiee;
private final String itemIthorian;
public RoadmapRewardInfo(SdbResultSet set) {
this.roadmapTemplateName = set.getText("roadmap_template_name");
this.roadmapSkillName = set.getText("roadmap_skill_name");
this.appearanceName = set.getText("appearance_name");
this.stringId = set.getText("string_id");
this.itemDefault = set.getText("item_default");
this.itemWookiee = set.getText("item_wookiee");
this.itemIthorian = set.getText("item_ithorian");
}
}
}

View File

@@ -0,0 +1,252 @@
/***********************************************************************************
* 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.resources.support.data.server_info.loader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public final class SkillLoader extends DataLoader {
private final Map<String, SkillInfo> skillsByName;
SkillLoader() {
this.skillsByName = new HashMap<>();
}
@Nullable
public SkillInfo getSkillByName(String name) {
return skillsByName.get(name);
}
@Override
public final void load() throws IOException {
try (SdbResultSet set = SdbLoader.load(new File("serverdata/skill/skills.sdb"))) {
while (set.next()) {
SkillInfo skills = new SkillInfo(set);
skillsByName.put(skills.getName(), skills);
}
}
}
@SuppressWarnings("ClassWithTooManyFields")
public static class SkillInfo {
private final String name;
private final String parent;
private final String graphType;
private final boolean godOnly;
private final boolean title;
private final boolean profession;
private final boolean hidden;
private final int moneyRequired;
private final int pointsRequired;
private final int skillsRequiredCount;
private final String [] skillsRequired;
private final String [] preclusionSkills;
private final String xpType;
private final int xpCost;
private final int xpCap;
private final String [] missionsRequired;
private final int apprenticeshipsRequired;
private final String [] statsRequired;
private final String [] speciesRequired;
private final String jediStateRequired;
private final String skillAbility;
private final String [] commands;
private final Map<String, Integer> skillMods;
private final String [] schematicsGranted;
private final String [] schematicsRevoked;
private final boolean searchable;
private final int ender;
public SkillInfo(SdbResultSet set) {
this.name = set.getText("name");
this.parent = set.getText("parent");
this.graphType = set.getText("graph_type");
this.godOnly = set.getBoolean("god_only");
this.title = set.getBoolean("is_title");
this.profession = set.getBoolean("is_profession");
this.hidden = set.getBoolean("is_hidden");
this.moneyRequired = (int) set.getInt("money_required");
this.pointsRequired = (int) set.getInt("points_required");
this.skillsRequiredCount = (int) set.getInt("skills_required_count");
this.skillsRequired = splitCsv(set.getText("skills_required"));
this.preclusionSkills = splitCsv(set.getText("preclusion_skills"));
this.xpType = set.getText("xp_type");
this.xpCost = (int) set.getInt("xp_cost");
this.xpCap = (int) set.getInt("xp_cap");
this.missionsRequired = splitCsv(set.getText("missions_required"));
this.apprenticeshipsRequired = (int) set.getInt("apprenticeships_required");
this.statsRequired = splitCsv(set.getText("stats_required"));
this.speciesRequired = splitCsv(set.getText("species_required"));
this.jediStateRequired = set.getText("jedi_state_required");
this.skillAbility = set.getText("skill_ability");
this.commands = splitCsv(set.getText("commands"));
this.skillMods = createSkillModMap(splitCsv(set.getText("skill_mods")));
this.schematicsGranted = splitCsv(set.getText("schematics_granted"));
this.schematicsRevoked = splitCsv(set.getText("schematics_revoked"));
this.searchable = set.getBoolean("searchable");
this.ender = (int) set.getInt("ender");
}
public String getName() {
return name;
}
public String getParent() {
return parent;
}
public String getGraphType() {
return graphType;
}
public boolean isGodOnly() {
return godOnly;
}
public boolean isTitle() {
return title;
}
public boolean isProfession() {
return profession;
}
public boolean isHidden() {
return hidden;
}
public int getMoneyRequired() {
return moneyRequired;
}
public int getPointsRequired() {
return pointsRequired;
}
public int getSkillsRequiredCount() {
return skillsRequiredCount;
}
public String[] getSkillsRequired() {
return skillsRequired.clone();
}
public String[] getPreclusionSkills() {
return preclusionSkills.clone();
}
public String getXpType() {
return xpType;
}
public int getXpCost() {
return xpCost;
}
public int getXpCap() {
return xpCap;
}
public String[] getMissionsRequired() {
return missionsRequired.clone();
}
public int getApprenticeshipsRequired() {
return apprenticeshipsRequired;
}
public String[] getStatsRequired() {
return statsRequired.clone();
}
public String[] getSpeciesRequired() {
return speciesRequired.clone();
}
public String getJediStateRequired() {
return jediStateRequired;
}
public String getSkillAbility() {
return skillAbility;
}
public String[] getCommands() {
return commands.clone();
}
public Map<String, Integer> getSkillMods() {
return Collections.unmodifiableMap(skillMods);
}
public String[] getSchematicsGranted() {
return schematicsGranted.clone();
}
public String[] getSchematicsRevoked() {
return schematicsRevoked.clone();
}
public boolean isSearchable() {
return searchable;
}
public int getEnder() {
return ender;
}
private static String [] splitCsv(String str) {
if (str.isEmpty())
return new String[0];
else if (str.indexOf(',') == -1)
return new String[]{str};
return str.split(",");
}
private static Map<String, Integer> createSkillModMap(String [] elements) {
Map<String, Integer> skillMods = new HashMap<>();
for (String element : elements) {
String [] split = element.split("=", 2);
if (split.length < 2)
continue;
skillMods.put(split[0], Integer.valueOf(split[1]));
}
return skillMods;
}
}
}

View File

@@ -0,0 +1,74 @@
/***********************************************************************************
* 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.resources.support.data.server_info.loader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader.SdbResultSet;
import java.io.File;
import java.io.IOException;
public final class SkillTemplateLoader extends DataLoader {
SkillTemplateLoader() {
}
@Override
public final void load() throws IOException {
try (SdbResultSet set = SdbLoader.load(new File("serverdata/skill/skill_template.sdb"))) {
while (set.next()) {
SkillTemplateInfo skillTemplate = new SkillTemplateInfo(set);
// TODO: Store information
}
}
}
public static class SkillTemplateInfo {
private final String templateName;
private final String startingTemplateName;
private final String strClassName;
private final int userInterfacePriority;
private final String template;
private final boolean levelBased;
private final String expertiseTrees;
private final int respecAllowed;
public SkillTemplateInfo(SdbResultSet set) {
this.templateName = set.getText("template_name");
this.startingTemplateName = set.getText("starting_template_name");
this.strClassName = set.getText("str_class_name");
this.userInterfacePriority = (int) set.getInt("user_interface_priority");
this.template = set.getText("template");
this.levelBased = set.getBoolean("level_based");
this.expertiseTrees = set.getText("expertise_trees");
this.respecAllowed = (int) set.getInt("respec_allowed");
}
}
}

View File

@@ -28,14 +28,16 @@ package com.projectswg.holocore.services.gameplay.player.experience;
import com.projectswg.common.data.info.RelationalDatabase;
import com.projectswg.common.data.info.RelationalServerFactory;
import com.projectswg.common.data.swgfile.ClientFactory;
import com.projectswg.common.data.swgfile.visitors.DatatableData;
import com.projectswg.common.network.packets.SWGPacket;
import com.projectswg.common.network.packets.swg.zone.ExpertiseRequestMessage;
import com.projectswg.holocore.intents.gameplay.player.experience.LevelChangedIntent;
import com.projectswg.holocore.intents.gameplay.player.experience.expertise.RequestExpertiseIntent;
import com.projectswg.holocore.intents.gameplay.player.experience.skills.GrantSkillIntent;
import com.projectswg.holocore.intents.support.global.network.InboundPacketIntent;
import com.projectswg.holocore.resources.support.data.server_info.StandardLog;
import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader;
import com.projectswg.holocore.resources.support.data.server_info.loader.ExpertiseLoader.ExpertiseInfo;
import com.projectswg.holocore.resources.support.data.server_info.loader.PlayerLevelLoader.PlayerLevelInfo;
import com.projectswg.holocore.resources.support.global.zone.sui.SuiButtons;
import com.projectswg.holocore.resources.support.global.zone.sui.SuiMessageBox;
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
@@ -47,75 +49,25 @@ import me.joshlarson.jlcommon.log.Log;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
*
* @author Mads
*/
public class ExperienceExpertiseService extends Service {
private static final String EXPERTISE_ABILITIES_QUERY = "SELECT * FROM expertise_abilities";
private final Map<String, Integer> expertiseSkills; // Expertise skill to tree ID
private final Map<Integer, Map<String, Expertise>> trees; // Tree ID to tree
private final Map<String, Collection<String[]>> expertiseAbilities; // Expertise skill to abilities
private final Map<Integer, Integer> pointsForLevel; // Level to points available
private final Map<String, Collection<String[]>> expertiseAbilities; // Expertise skill to abilities
public ExperienceExpertiseService() {
trees = new HashMap<>();
expertiseSkills = new HashMap<>();
expertiseAbilities = new HashMap<>();
pointsForLevel = new HashMap<>();
this.expertiseAbilities = new HashMap<>();
}
@Override
public boolean initialize() {
loadTrees();
loadPointsForLevel();
return super.initialize() && loadExpertise() && loadAbilities();
}
private void loadTrees() {
long startTime = StandardLog.onStartLoad("expertise trees");
DatatableData expertiseTable = (DatatableData) ClientFactory.getInfoFromFile("datatables/expertise/expertise_trees.iff");
int rowCount = expertiseTable.getRowCount();
for (int i = 0; i < rowCount; i++) {
int treeId = (int) expertiseTable.getCell(i, 0);
trees.put(treeId, new HashMap<>());
}
StandardLog.onEndLoad(rowCount, "expertise trees", startTime);
}
private boolean loadExpertise() {
long startTime = StandardLog.onStartLoad("expertise skills");
DatatableData expertiseTable = (DatatableData) ClientFactory.getInfoFromFile("datatables/expertise/expertise.iff");
int rowCount = expertiseTable.getRowCount();
for (int i = 0; i < rowCount; i++) {
String skillName = (String) expertiseTable.getCell(i, 0);
int treeId = (int) expertiseTable.getCell(i, 1);
Map<String, Expertise> expertise = trees.get(treeId);
if (expertise == null) {
Log.e("Expertise %s refers to unknown tree with ID %d", skillName, treeId);
return false;
}
expertiseSkills.put(skillName, treeId);
String requiredProfession = formatProfession((String) expertiseTable.getCell(i, 7));
int tier = (int) expertiseTable.getCell(i, 2);
expertise.put(skillName, new Expertise(requiredProfession, tier));
}
StandardLog.onEndLoad(rowCount, "expertise skills", startTime);
return true;
return loadAbilities();
}
private boolean loadAbilities() {
@@ -148,18 +100,6 @@ public class ExperienceExpertiseService extends Service {
return true;
}
private void loadPointsForLevel() {
DatatableData playerLevelTable = (DatatableData) ClientFactory.getInfoFromFile("datatables/player/player_level.iff");
int points = 0;
for (int i = 0; i < playerLevelTable.getRowCount(); i++) {
int level = (int) playerLevelTable.getCell(i, 0);
points += (int) playerLevelTable.getCell(i, 5);
pointsForLevel.put(level, points);
}
}
@IntentHandler
private void handleInboundPacketIntent(InboundPacketIntent gpi) {
SWGPacket packet = gpi.getPacket();
@@ -168,43 +108,51 @@ public class ExperienceExpertiseService extends Service {
return;
}
ExpertiseRequestMessage expertiseRequestMessage = (ExpertiseRequestMessage) packet;
CreatureObject creatureObject = gpi.getPlayer().getCreatureObject();
String[] requestedSkills = expertiseRequestMessage.getRequestedSkills();
for (String requestedSkill : requestedSkills) {
if (creatureObject == null)
return;
ExpertiseRequestMessage request = (ExpertiseRequestMessage) packet;
RequestExpertiseIntent.broadcast(creatureObject, Arrays.stream(request.getRequestedSkills())
.map(DataLoader.expertise()::getByName)
.filter(Objects::nonNull)
.collect(Collectors.toList()));
}
@IntentHandler
private void handleRequestExpertiseIntent(RequestExpertiseIntent rei) {
CreatureObject creatureObject = rei.getCreature();
checkExtraAbilities(creatureObject);
int index = -1;
for (ExpertiseInfo expertise : rei.getExpertise()) {
index++;
if (getAvailablePoints(creatureObject) < 1) {
Log.i("%s attempted to spend more expertise points than available to them", creatureObject);
StandardLog.onPlayerError(this, creatureObject, "attempted to spend more expertise points than available to them");
return;
}
// TODO do anything with clearAllExpertisesFirst?
Integer treeId = expertiseSkills.get(requestedSkill);
if (treeId == null) {
continue;
}
PlayerObject playerObject = creatureObject.getPlayerObject();
String profession = playerObject.getProfession();
Map<String, Expertise> tree = trees.get(treeId);
Expertise expertise = tree.get(requestedSkill);
if (!expertise.getRequiredProfession().equals(profession)) {
Log.i("%s attempted to train expertise skill %s as the wrong profession", creatureObject, requestedSkill);
continue;
}
int requiredTreePoints = (expertise.getTier() - 1) * 4;
if (requiredTreePoints > getPointsInTree(tree, creatureObject)) {
Log.i("%s attempted to train expertise skill %s without having unlocked the tier of the tree", creatureObject, requestedSkill);
StandardLog.onPlayerError(this, creatureObject, "attempted to train expertise skill %s as the wrong profession", expertise.getName());
continue;
}
Intent intent = new GrantSkillIntent(GrantSkillIntent.IntentType.GRANT, requestedSkill, creatureObject, false);
intent.broadcast();
while (!intent.isComplete()); // Block until the GrantSkillIntent has been processed
int requiredTreePoints = (expertise.getTier() - 1) * 4;
if (requiredTreePoints > getPointsInTree(expertise, creatureObject)) {
StandardLog.onPlayerError(this, creatureObject, "attempted to train expertise skill %s without having unlocked the tier of the tree", expertise.getName());
continue;
}
// After the grant is processed, try adding the next expertise
Intent grant = new GrantSkillIntent(GrantSkillIntent.IntentType.GRANT, expertise.getName(), creatureObject, false);
Intent recursive = new RequestExpertiseIntent(rei.getCreature(), rei.getExpertise().subList(index+1, rei.getExpertise().size()));
recursive.broadcastAfterIntent(grant);
grant.broadcast();
break;
}
checkExtraAbilities(creatureObject);
@@ -216,14 +164,14 @@ public class ExperienceExpertiseService extends Service {
CreatureObject creatureObject = lci.getCreatureObject();
PlayerObject playerObject = creatureObject.getPlayerObject();
short oldLevel = lci.getPreviousLevel();
if (oldLevel < 10 && newLevel >= 10) {
SuiMessageBox window = new SuiMessageBox(SuiButtons.OK, "@expertise_d:sui_expertise_introduction_title", "@expertise_d:sui_expertise_introduction_body");
SuiMessageBox window = new SuiMessageBox(SuiButtons.OK, "@expertise_d:sui_expertise_introduction_title", "@expertise_d:sui_expertise_introduction_body");
window.display(playerObject.getOwner());
// If we don't add the expertise root skill, the creature can't learn child skills
creatureObject.addSkill("expertise");
}
checkExtraAbilities(creatureObject);
}
@@ -238,22 +186,21 @@ public class ExperienceExpertiseService extends Service {
}
private void checkExtraAbilities(CreatureObject creatureObject) {
creatureObject.getSkills().stream()
.filter(expertiseAbilities::containsKey) // We only want to check skills that give additional abilities
creatureObject.getSkills().stream().filter(expertiseAbilities::containsKey) // We only want to check skills that give additional abilities
.forEach(expertise -> grantExtraAbilities(creatureObject, expertise));
}
private boolean isQualified(CreatureObject creatureObject, int abilityIndex) {
int baseRequirement = 18;
int levelDifference = 12; // Amount of levels between each ability
int levelDifference = 12; // Amount of levels between each ability
int level = creatureObject.getLevel();
// All first rank abilities have a required level of 10
// The required level logic is required for ranks 2+
if (abilityIndex == 0) {
return level >= 10;
}
// Otherwise, perform the check as usual
int requiredLevel = baseRequirement + abilityIndex * levelDifference;
@@ -273,55 +220,19 @@ public class ExperienceExpertiseService extends Service {
});
}
private String formatProfession(String profession) {
switch (profession) {
case "trader_dom": return "trader_0a";
case "trader_struct": return "trader_0b";
case "trader_mun": return "trader_0c";
case "trader_eng": return "trader_0d";
default: return profession + "_1a";
}
}
private int getAvailablePoints(CreatureObject creatureObject) {
int levelPoints = pointsForLevel.get((int) creatureObject.getLevel());
int spentPoints = (int) creatureObject.getSkills().stream()
.filter(skill -> skill.startsWith("expertise_"))
.count();
PlayerLevelInfo levelInfo = DataLoader.playerLevels().getFromLevel(creatureObject.getLevel());
int spentPoints = (int) creatureObject.getSkills().stream().filter(skill -> skill.startsWith("expertise_")).count();
return levelPoints - spentPoints;
Objects.requireNonNull(levelInfo, "No player level defined for " + creatureObject.getLevel());
return levelInfo.getExpertisePoints() - spentPoints;
}
/**
*
* @param tree
* @param creatureObject
* @return the amount of expertise points invested in a given expertise tree
*/
private long getPointsInTree(Map<String, Expertise> tree, CreatureObject creatureObject) {
return tree.keySet().stream()
.filter(creatureObject.getSkills()::contains)
.count();
}
private static class Expertise {
private final String requiredProfession;
private final int tier;
public Expertise(String requiredProfession, int tier) {
this.requiredProfession = requiredProfession;
this.tier = tier;
}
public String getRequiredProfession() {
return requiredProfession;
}
public int getTier() {
return tier;
}
private long getPointsInTree(ExpertiseInfo expertise, CreatureObject creatureObject) {
return DataLoader.expertise().getPeerExpertise(expertise).stream().map(ExpertiseInfo::getName).filter(creatureObject.getSkills()::contains).count();
}
}

View File

@@ -1,64 +1,19 @@
package com.projectswg.holocore.services.gameplay.player.experience.skills;
import com.projectswg.common.data.swgfile.ClientFactory;
import com.projectswg.common.data.swgfile.visitors.DatatableData;
import com.projectswg.holocore.intents.gameplay.player.badge.SetTitleIntent;
import com.projectswg.holocore.intents.gameplay.player.experience.skills.GrantSkillIntent;
import com.projectswg.holocore.intents.gameplay.player.experience.skills.SkillModIntent;
import com.projectswg.holocore.resources.support.data.server_info.StandardLog;
import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader;
import com.projectswg.holocore.resources.support.data.server_info.loader.SkillLoader.SkillInfo;
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
import me.joshlarson.jlcommon.control.IntentHandler;
import me.joshlarson.jlcommon.control.Service;
import me.joshlarson.jlcommon.log.Log;
import java.util.HashMap;
import java.util.Map;
public class SkillService extends Service {
private final Map<String, SkillData> skillDataMap;
public SkillService() {
skillDataMap = new HashMap<>();
}
@Override
public boolean initialize() {
DatatableData skillsTable = (DatatableData) ClientFactory.getInfoFromFile("datatables/skill/skills.iff");
for (int i = 0; i < skillsTable.getRowCount(); i++) {
String skillName = (String) skillsTable.getCell(i, 0);
String [] skillModsStrings = splitCsv((String) skillsTable.getCell(i, 22));
Map<String, Integer> skillMods = new HashMap<>();
for (String skillModString : skillModsStrings) {
String [] values = skillModString.split("=", 2);
skillMods.put(values[0], Integer.parseInt(values[1]));
}
SkillData skillData = new SkillData(
(boolean) skillsTable.getCell(i, 4), // Is title
splitCsv((String) skillsTable.getCell(i, 10)), // required skills
(String) skillsTable.getCell(i, 1), // parent skill
(String) skillsTable.getCell(i, 12), // xp type
(int) skillsTable.getCell(i, 13), // xp cost
splitCsv((String) skillsTable.getCell(i, 21)), // commands
skillMods,
splitCsv((String) skillsTable.getCell(i, 23)) // schematics
);
skillDataMap.put(skillName, skillData);
}
return true;
}
private void loadSkills() {
}
private String [] splitCsv(String str) {
if (str.isEmpty())
return new String[0];
else if (str.indexOf(',') == -1)
return new String[]{str};
return str.split(",");
}
@IntentHandler
@@ -69,14 +24,17 @@ public class SkillService extends Service {
String skillName = gsi.getSkillName();
CreatureObject target = gsi.getTarget();
SkillData skillData = skillDataMap.get(skillName);
String parentSkillName = skillData.getParentSkill();
SkillInfo skillData = DataLoader.skills().getSkillByName(skillName);
if (skillData == null)
return;
String parentSkillName = skillData.getParent();
if (gsi.isGrantRequiredSkills()) {
grantParentSkills(skillData, parentSkillName, target);
grantRequiredSkills(skillData, target);
} else if (!target.hasSkill(parentSkillName) || !hasRequiredSkills(skillData, target)) {
Log.i("%s lacks required skill %s before being granted skill %s", target, parentSkillName, skillName);
StandardLog.onPlayerError(this, target, "lacks required skill %s before being granted skill %s", parentSkillName, skillName);
return;
}
@@ -87,13 +45,12 @@ public class SkillService extends Service {
private void handleSetTitleIntent(SetTitleIntent sti) {
String title = sti.getTitle();
if (!skillDataMap.containsKey(title)) {
SkillInfo skillData = DataLoader.skills().getSkillByName(title);
if (skillData == null) {
// Might be a Collections title or someone playing tricks
return;
}
SkillData skillData = skillDataMap.get(title);
if (!skillData.isTitle()) {
// There's a skill with this name, but it doesn't grant a title
return;
@@ -102,8 +59,8 @@ public class SkillService extends Service {
sti.getRequester().setTitle(title);
}
private boolean hasRequiredSkills(SkillData skillData, CreatureObject creatureObject) {
String[] requiredSkills = skillData.getRequiredSkills();
private boolean hasRequiredSkills(SkillInfo skillData, CreatureObject creatureObject) {
String[] requiredSkills = skillData.getSkillsRequired();
if (requiredSkills == null)
return true;
@@ -114,25 +71,28 @@ public class SkillService extends Service {
return true;
}
private void grantParentSkills(SkillData skillData, String parentSkill, CreatureObject target) {
if (skillData == null || parentSkill.isEmpty() || target.hasSkill(parentSkill)) {
private void grantParentSkills(SkillInfo skillData, String parentSkill, CreatureObject target) {
if (skillData == null || parentSkill.isEmpty() || target.hasSkill(parentSkill))
return;
}
SkillInfo skillParent = DataLoader.skills().getSkillByName(parentSkill);
if (skillParent == null)
return;
grantSkill(skillData, parentSkill, target);
String grandParentSkill = skillData.getParentSkill();
grantParentSkills(skillDataMap.get(grandParentSkill), grandParentSkill, target);
String grandParentSkill = skillData.getParent();
grantParentSkills(skillParent, grandParentSkill, target);
}
private void grantRequiredSkills(SkillData skillData, CreatureObject target) {
String[] requiredSkills = skillData.getRequiredSkills();
private void grantRequiredSkills(SkillInfo skillData, CreatureObject target) {
String[] requiredSkills = skillData.getSkillsRequired();
if (requiredSkills == null)
return;
target.addSkill(requiredSkills);
}
private void grantSkill(SkillData skillData, String skillName, CreatureObject target) {
private void grantSkill(SkillInfo skillData, String skillName, CreatureObject target) {
target.addSkill(skillName);
target.addAbility(skillData.getCommands());
@@ -141,35 +101,4 @@ public class SkillService extends Service {
new GrantSkillIntent(GrantSkillIntent.IntentType.GIVEN, skillName, target, false).broadcast();
}
private static class SkillData {
private boolean title;
private String[] requiredSkills;
private final String parentSkill;
private final String xpType;
private final int xpCost;
private final String[] commands;
private final Map<String, Integer> skillMods;
private final String[] schematics;
public SkillData(boolean title, String[] requiredSkills, String parentSkill, String xpType, int xpCost, String[] commands, Map<String, Integer> skillMods, String[] schematics) {
this.title = title;
this.requiredSkills = requiredSkills;
this.parentSkill = parentSkill;
this.xpType = xpType;
this.xpCost = xpCost;
this.commands = commands;
this.skillMods = skillMods;
this.schematics = schematics;
}
private boolean isTitle() { return title; }
public String[] getRequiredSkills() { return requiredSkills; }
public String getParentSkill() { return parentSkill; }
public String getXpType() { return xpType; }
public int getXpCost() { return xpCost; }
public String[] getCommands() { return commands; }
public Map<String, Integer> getSkillMods() { return skillMods; }
public String[] getSchematics() { return schematics; }
}
}

View File

@@ -0,0 +1,165 @@
/***********************************************************************************
* 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.common.network.packets.swg.zone.ExpertiseRequestMessage;
import com.projectswg.holocore.intents.gameplay.player.experience.LevelChangedIntent;
import com.projectswg.holocore.intents.support.global.network.InboundPacketIntent;
import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader;
import com.projectswg.holocore.resources.support.data.server_info.loader.ExpertiseLoader.ExpertiseInfo;
import com.projectswg.holocore.resources.support.global.player.Player;
import com.projectswg.holocore.resources.support.objects.swg.player.PlayerObject;
import com.projectswg.holocore.services.gameplay.player.experience.skills.SkillService;
import com.projectswg.holocore.test.resources.GenericCreatureObject;
import com.projectswg.holocore.test.runners.TestRunnerSynchronousIntents;
import org.junit.Assert;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
public class TestExperienceExpertiseService extends TestRunnerSynchronousIntents {
@Test
public void testRequestExpertiseWrongProfession() {
registerService(new ExperienceExpertiseService());
registerService(new SkillService());
GenericCreatureObject creature = new GenericCreatureObject(1);
PlayerObject player = creature.getPlayerObject();
Player owner = creature.getOwner();
Assert.assertNotNull(player);
Assert.assertNotNull(owner);
player.setProfession("medic_1a");
// Nothing defined
broadcastAndWait(new InboundPacketIntent(owner, new ExpertiseRequestMessage(new String[]{}, false)));
Assert.assertEquals(Set.of(), creature.getSkills());
Assert.assertEquals(Set.of(), creature.getAbilityNames());
// No expertise yet
broadcastAndWait(new InboundPacketIntent(owner, new ExpertiseRequestMessage(new String[]{"expertise_fs_general_enhanced_strength_1"}, false)));
Assert.assertEquals(Set.of(), creature.getSkills());
Assert.assertEquals(Set.of(), creature.getAbilityNames());
// Wrong profession
creature.setLevel(90);
broadcastAndWait(new LevelChangedIntent(creature, (short) 1, (short) 90));
broadcastAndWait(new InboundPacketIntent(owner, new ExpertiseRequestMessage(new String[]{"expertise_fs_general_enhanced_strength_1"}, false)));
Assert.assertEquals(Set.of("expertise"), creature.getSkills());
Assert.assertEquals(Set.of(), creature.getAbilityNames());
}
@Test
public void testRequestExpertise() {
registerService(new ExperienceExpertiseService());
registerService(new SkillService());
GenericCreatureObject creature = new GenericCreatureObject(1);
PlayerObject player = creature.getPlayerObject();
Player owner = creature.getOwner();
Assert.assertNotNull(player);
Assert.assertNotNull(owner);
player.setProfession("force_sensitive_1a");
// Nothing defined
broadcastAndWait(new InboundPacketIntent(owner, new ExpertiseRequestMessage(new String[]{}, false)));
Assert.assertEquals(Set.of(), creature.getSkills());
Assert.assertEquals(Set.of(), creature.getAbilityNames());
// No expertise yet
broadcastAndWait(new InboundPacketIntent(owner, new ExpertiseRequestMessage(new String[]{"expertise_fs_general_enhanced_strength_1"}, false)));
Assert.assertEquals(Set.of(), creature.getSkills());
Assert.assertEquals(Set.of(), creature.getAbilityNames());
// Haven't unlocked tier
creature.setLevel(10);
broadcastAndWait(new LevelChangedIntent(creature, (short) 1, (short) 10));
broadcastAndWait(new InboundPacketIntent(owner, new ExpertiseRequestMessage(new String[]{"expertise_fs_general_improved_force_throw_1"}, false)));
Assert.assertEquals(Set.of("expertise"), creature.getSkills());
Assert.assertEquals(Set.of(), creature.getAbilityNames());
// Success
creature.setLevel(90);
broadcastAndWait(new LevelChangedIntent(creature, (short) 10, (short) 90));
String [] expertiseRequest = new String[]{
"expertise",
"expertise_fs_general_enhanced_strength_1",
"expertise_fs_general_enhanced_strength_2",
"expertise_fs_general_enhanced_constitution_1",
"expertise_fs_general_enhanced_constitution_2",
"expertise_fs_general_improved_force_throw_1"
};
broadcastAndWait(new InboundPacketIntent(owner, new ExpertiseRequestMessage(expertiseRequest, false)));
Assert.assertEquals(Set.of(expertiseRequest), creature.getSkills());
Assert.assertEquals(Set.of(), creature.getAbilityNames());
}
@Test
public void testFullTree() {
registerService(new ExperienceExpertiseService());
registerService(new SkillService());
for (String profession : new String[]{"bounty_hunter_1a", "commando_1a", "entertainer_1a", "force_sensitive_1a", "medic_1a", "officer_1a", "smuggler_1a", "spy_1a", "trader_1a", "trader_1b", "trader_1c", "trader_1d"}) {
GenericCreatureObject creature = new GenericCreatureObject(1, profession);
PlayerObject player = creature.getPlayerObject();
Player owner = creature.getOwner();
Assert.assertNotNull(player);
Assert.assertNotNull(owner);
player.setProfession(profession);
creature.setLevel(90);
broadcastAndWait(new LevelChangedIntent(creature, (short) 1, (short) 90));
List<ExpertiseInfo> sortedExpertise = DataLoader.expertise().getAllExpertise().stream()
.filter(e -> e.getRequiredProfession().equals(profession))
.filter(e -> e.getTree().getUiBackgroundId().equals("left"))
.sorted(Comparator.comparingInt(ExpertiseInfo::getTier).thenComparing(ExpertiseInfo::getGrid).thenComparing(ExpertiseInfo::getRank))
.collect(Collectors.toList());
List<String> expectedExpertise = new ArrayList<>(); // the list we verify with
List<String> requestExpertise = new ArrayList<>(); // the list sent to the service
int usedPoints = 0;
expectedExpertise.add("expertise");
for (ExpertiseInfo expertise : sortedExpertise) {
expectedExpertise.add(expertise.getName());
requestExpertise.add(expertise.getName());
usedPoints++;
if (usedPoints >= 45)
break;
}
broadcastAndWait(new InboundPacketIntent(owner, new ExpertiseRequestMessage(requestExpertise.toArray(String[]::new), false)));
Assert.assertEquals("Failed on: " + profession, new HashSet<>(expectedExpertise), creature.getSkills());
}
}
}