Merged quality_assurance into buffs

This commit is contained in:
Mads Boddum
2016-01-20 11:53:52 +01:00
117 changed files with 142843 additions and 128891 deletions
BIN
View File
Binary file not shown.
+4
View File
@@ -56,6 +56,10 @@ from the Sonatype site.
- test - Does all that 'compile' does, plus runs the unit tests
- package - Does all that 'test' does but generates all of the artifacts
### Forwarder ###
Holocore uses TCP for network communications, whereas SWG was programmed for UDP. This adds numerous efficiencies with long distance communications, but requires that a little more work is done on the client side. If you are using the launcher, you do not have to worry about this. If you are not using the launcher, follow the guide [here](https://bitbucket.org/projectswg/forwarder).
### Running Holocore ###
In order to successfully build and run Holocore, you must:
BIN
View File
Binary file not shown.
+8 -3
View File
@@ -44,9 +44,14 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.12</version>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>net.jpountz.lz4</groupId>
<artifactId>lz4</artifactId>
<version>1.3.0</version>
</dependency>
</dependencies>
+1 -1
View File
@@ -1,4 +1,4 @@
var execute = function(galManager, player, target, args) {
function executeCommand(galacticManager, player, target, args) {
var creature = player.getCreatureObject();
var PvpFaction = Java.type("resources.PvpFaction");
var FactionIntent = Java.type("intents.FactionIntent");
+5 -8
View File
@@ -14,14 +14,11 @@ function executeCommand(galacticManager, player, target, args) {
return;
}
if(target.getParent() == actor) {
result = target.moveToContainer(actor, inventory);
actor.removeEquipment(target)
} else {
result = target.moveToContainer(actor, actor);
actor.addEquipment(target)
result = target.moveToContainer(actor, newContainer); // Move item from the old container to the new container
if (actor.getEquipmentList().contains(target)) {
actor.removeEquipment(target);
} else if (newContainer == actor) {
actor.addEquipment(target);
}
result = target.moveToContainer(actor, newContainer); // Move item from the old container to the new container
}
@@ -0,0 +1,191 @@
command player csr qa dev
TEXT TEXT TEXT TEXT TEXT
activateInstance FALSE TRUE TRUE TRUE
activateQuest FALSE TRUE TRUE TRUE
addAllowedPlayer FALSE TRUE TRUE TRUE
addBannedPlayer FALSE TRUE TRUE TRUE
adjustLotCount FALSE TRUE TRUE TRUE
aiIgnore FALSE TRUE TRUE TRUE
broadcast FALSE TRUE TRUE TRUE
broadcastArea FALSE TRUE TRUE TRUE
broadcastGalaxy FALSE TRUE TRUE TRUE
broadcastPlanet FALSE TRUE TRUE TRUE
cityInfo FALSE TRUE TRUE TRUE
clearCompletedQuest FALSE TRUE TRUE TRUE
clearVeteranReward FALSE TRUE TRUE TRUE
combatDataClear FALSE TRUE TRUE TRUE
combatDataRecord FALSE TRUE TRUE TRUE
combatDataReport FALSE TRUE TRUE TRUE
combatDataStop FALSE TRUE TRUE TRUE
completeRestussStageOne FALSE TRUE TRUE TRUE
craft FALSE TRUE TRUE TRUE
createCreature FALSE TRUE TRUE TRUE
createMissionElement FALSE TRUE TRUE TRUE
createNPC FALSE TRUE TRUE TRUE
createSpawningElement FALSE TRUE TRUE TRUE
createSpawningElementWithDifficulty FALSE TRUE TRUE TRUE
createStaticItem FALSE TRUE TRUE TRUE
credits FALSE TRUE TRUE TRUE
csDumpTarget FALSE TRUE TRUE TRUE
csStorytellerDestroyAllObjects FALSE TRUE TRUE TRUE
csStorytellerDestroyNpcs FALSE TRUE TRUE TRUE
csStorytellerDestroyParticles FALSE TRUE TRUE TRUE
csStorytellerDestroyProps FALSE TRUE TRUE TRUE
database FALSE TRUE TRUE TRUE
deactivateQuest FALSE TRUE TRUE TRUE
destroy FALSE TRUE TRUE TRUE
dumpObjectInformation FALSE TRUE TRUE TRUE
dumpTargetInformation FALSE TRUE TRUE TRUE
dumpZoneInformation FALSE TRUE TRUE TRUE
editAppearance FALSE TRUE TRUE TRUE
editBank FALSE TRUE TRUE TRUE
editBankAccount FALSE TRUE TRUE TRUE
editStats FALSE TRUE TRUE TRUE
emptyMailTarget FALSE TRUE TRUE TRUE
eventBuff FALSE TRUE TRUE TRUE
eventBuffArea FALSE TRUE TRUE TRUE
eventBuffTarget FALSE TRUE TRUE TRUE
eventClearStates FALSE TRUE TRUE TRUE
eventDamage FALSE TRUE TRUE TRUE
eventMoveToMe FALSE TRUE TRUE TRUE
eventShuttleDrop FALSE TRUE TRUE TRUE
eventStartRaid FALSE TRUE TRUE TRUE
eventStorePet FALSE TRUE TRUE TRUE
eventTefArea FALSE TRUE TRUE TRUE
eventTefClear FALSE TRUE TRUE TRUE
eventTefTarget FALSE TRUE TRUE TRUE
eventUndoMoveToMe FALSE TRUE TRUE TRUE
eventVaderChoke FALSE TRUE TRUE TRUE
eventWeapon FALSE TRUE TRUE TRUE
findCreature FALSE TRUE TRUE TRUE
findObject FALSE TRUE TRUE TRUE
findObjectByTemplate FALSE TRUE TRUE TRUE
findPlayer FALSE TRUE TRUE TRUE
findWarden FALSE TRUE TRUE TRUE
forceCommand FALSE TRUE TRUE TRUE
freezePlayer FALSE TRUE TRUE TRUE
generateCraftedItem FALSE TRUE TRUE TRUE
getAccountInfo FALSE TRUE TRUE TRUE
getGameTime FALSE TRUE TRUE TRUE
getObjVars FALSE TRUE TRUE TRUE
getPlayerId FALSE TRUE TRUE TRUE
getRank FALSE TRUE TRUE TRUE
getSpawnDelays FALSE TRUE TRUE TRUE
getStationName FALSE TRUE TRUE TRUE
getVeteranRewardTimeCs FALSE TRUE TRUE TRUE
gmClearQuest FALSE TRUE TRUE TRUE
gmCreateClassResource FALSE TRUE TRUE TRUE
gmCreateSpecificResource FALSE TRUE TRUE TRUE
gmForceCommand FALSE TRUE TRUE TRUE
gmForceRank FALSE TRUE TRUE TRUE
gmFsVillage FALSE TRUE TRUE TRUE
gmGrantQuest FALSE TRUE TRUE TRUE
gmJediState FALSE TRUE TRUE TRUE
gmr FALSE TRUE TRUE TRUE
gmregrantQuest FALSE TRUE TRUE TRUE
gmRevive FALSE TRUE TRUE TRUE
gmShowQuest FALSE TRUE TRUE TRUE
gmSpawnShip FALSE TRUE TRUE TRUE
gmWeapon FALSE TRUE TRUE TRUE
goto FALSE TRUE TRUE TRUE
grantBadge FALSE TRUE TRUE TRUE
grantBadgeArea FALSE TRUE TRUE TRUE
grantPadawanTrialsEligibility FALSE TRUE TRUE TRUE
grantSkill FALSE TRUE TRUE TRUE
grantTitle FALSE TRUE TRUE TRUE
grantWarden FALSE TRUE TRUE TRUE
harmful FALSE TRUE TRUE TRUE
harmless FALSE TRUE TRUE TRUE
hasVeteranReward FALSE TRUE TRUE TRUE
initializeComponent FALSE TRUE TRUE TRUE
invulnerable FALSE TRUE TRUE TRUE
kick FALSE TRUE TRUE TRUE
kill FALSE TRUE TRUE TRUE
killPlayer FALSE TRUE TRUE TRUE
lag FALSE TRUE TRUE TRUE
listActiveQuests FALSE TRUE TRUE TRUE
listCompletedQuests FALSE TRUE TRUE TRUE
listGuilds FALSE TRUE TRUE TRUE
manufacture FALSE TRUE TRUE TRUE
maxCombatAbility FALSE TRUE TRUE TRUE
maxForcePower FALSE TRUE TRUE TRUE
maxStats FALSE TRUE TRUE TRUE
money FALSE TRUE TRUE TRUE
npc FALSE TRUE TRUE TRUE
npeGotoMedicalBay FALSE TRUE TRUE TRUE
npeGotoMilleniumFalcon FALSE TRUE TRUE TRUE
npeGotoStationGamma FALSE TRUE TRUE TRUE
npeGotoTansariiStation FALSE TRUE TRUE TRUE
object FALSE TRUE TRUE TRUE
objvar FALSE TRUE TRUE TRUE
overrideActiveMonths FALSE TRUE TRUE TRUE
overridePadawanTrialsEligibility FALSE TRUE TRUE TRUE
planetwarp FALSE TRUE TRUE TRUE
planetwarpTarget FALSE TRUE TRUE TRUE
qatool FALSE TRUE TRUE TRUE
qatool FALSE TRUE TRUE TRUE
reconnectToTransferServer FALSE TRUE TRUE TRUE
remote FALSE TRUE TRUE TRUE
removeAllowedPlayer FALSE TRUE TRUE TRUE
removeBannedPlayer FALSE TRUE TRUE TRUE
resendLoginMessageToAll FALSE TRUE TRUE TRUE
resetCooldowns FALSE TRUE TRUE TRUE
resetJedi FALSE TRUE TRUE TRUE
resource FALSE TRUE TRUE TRUE
resourceSetName FALSE TRUE TRUE TRUE
revertPlayerAppearance FALSE TRUE TRUE TRUE
revokeBadge FALSE TRUE TRUE TRUE
revokeSkill FALSE TRUE TRUE TRUE
revokeWarden FALSE TRUE TRUE TRUE
script FALSE TRUE TRUE TRUE
searchCorpse FALSE TRUE TRUE TRUE
secretSpawnSpam FALSE TRUE TRUE TRUE
server FALSE TRUE TRUE TRUE
setExperience FALSE TRUE TRUE TRUE
setFaction FALSE TRUE TRUE TRUE
setFactionStanding FALSE TRUE TRUE TRUE
setFirstName FALSE TRUE TRUE TRUE
setGrievousAuthorized FALSE TRUE TRUE TRUE
setGroupXPBonus FALSE TRUE TRUE TRUE
setHue FALSE TRUE TRUE TRUE
setInstanceAuthorized FALSE TRUE TRUE TRUE
setLastName FALSE TRUE TRUE TRUE
setLoginMessage FALSE TRUE TRUE TRUE
setLoginTitle FALSE TRUE TRUE TRUE
setMaximumSpawnTime FALSE TRUE TRUE TRUE
setMinimumSpawnTime FALSE TRUE TRUE TRUE
setName FALSE TRUE TRUE TRUE
setOwner FALSE TRUE TRUE TRUE
setPlanetLimit FALSE TRUE TRUE TRUE
setPlayerAppearance FALSE TRUE TRUE TRUE
setPlayerState FALSE TRUE TRUE TRUE
setPublicState FALSE TRUE TRUE TRUE
setRank FALSE TRUE TRUE TRUE
setSpeed FALSE TRUE TRUE TRUE
setTEF FALSE TRUE TRUE TRUE
setVeteranReward FALSE TRUE TRUE TRUE
setWardenLoginMessage FALSE TRUE TRUE TRUE
showFactionInformation FALSE TRUE TRUE TRUE
showSpawnRegion FALSE TRUE TRUE TRUE
skill FALSE TRUE TRUE TRUE
snoop FALSE TRUE TRUE TRUE
spawnStatus FALSE TRUE TRUE TRUE
spewCommandQueue FALSE TRUE TRUE TRUE
squelch FALSE TRUE TRUE TRUE
startCitySpawner FALSE TRUE TRUE TRUE
startRestussStageTwo FALSE TRUE TRUE TRUE
startSpawner FALSE TRUE TRUE TRUE
startTargetSpawner FALSE TRUE TRUE TRUE
startTraceLogging FALSE TRUE TRUE TRUE
stopCitySpawner FALSE TRUE TRUE TRUE
stopSpawner FALSE TRUE TRUE TRUE
stopTargetSpawner FALSE TRUE TRUE TRUE
stopTraceLogging FALSE TRUE TRUE TRUE
teleport FALSE TRUE TRUE TRUE
teleportTarget FALSE TRUE TRUE TRUE
teleportTo FALSE TRUE TRUE TRUE
unCityBan FALSE TRUE TRUE TRUE
unfreezePlayer FALSE TRUE TRUE TRUE
unsnoop FALSE TRUE TRUE TRUE
unsquelch FALSE TRUE TRUE TRUE
wipeItems FALSE TRUE TRUE TRUE
+118114 -118114
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,110 @@
factionName playerAllowed isAggro isPvP pvpFaction enemies allies combatFactor
TEXT TEXT TEXT TEXT TEXT TEXT TEXT FLOAT
Imperial TRUE TRUE TRUE imperial Rebel - 1
Rebel TRUE TRUE TRUE rebel Imperial - 1
Hutt TRUE TRUE FALSE - naboo_security_force,nym,Imperial,corsec,narmle jabba,borvo 1
ImperialCitizen FALSE FALSE FALSE - - - 1
RebelCitizen FALSE FALSE FALSE - - - 1
Neutral FALSE FALSE FALSE - - - 1
Unattackable FALSE FALSE FALSE unattackable - - 1
clone_relics_claw FALSE FALSE FALSE - - - 1
clone_relics_droid FALSE TRUE FALSE - clone_relics_scientist - 1
clone_relics_scientist FALSE FALSE FALSE - clone_relics_droid Hutt,Imperial,Rebel 1
afarathu TRUE TRUE FALSE - corsec,survivor - 1
beldonnas_league TRUE TRUE FALSE - followers_of_lord_nyax,lost_aqualish corsec 1
corsec TRUE TRUE FALSE - afarathu,followers_of_lord_nyax,monumenter,rogue_corsec,lost_aqualish beldonnas_league 1
followers_of_lord_nyax TRUE TRUE FALSE - corsec,beldonnas_league - 1
hidden_daggers TRUE TRUE FALSE - corsec,beldonnas_league,flail rogue_corsec 1
meatlump TRUE TRUE FALSE - corsec,rogue_corsec,beldonnas_league - 1
monumenter TRUE TRUE FALSE - corsec,beldonnas_league - 1
olag_greck TRUE TRUE FALSE - corsec,beldonnas_league - 1
rogue_corsec TRUE TRUE FALSE - corsec hidden_daggers 1
smashball TRUE TRUE FALSE - corsec,cor_swoop - 1
dantari_raiders TRUE TRUE FALSE - kunga_tribe,mokk_tribe,janta_tribe - 1
janta_tribe TRUE TRUE FALSE - kunga_tribe,dantari_raiders - 1
kunga_tribe TRUE TRUE FALSE - mokk_tribe,dantari_raiders - 1
mokk_tribe TRUE TRUE FALSE - janta_tribe,dantari_raiders - 1
nightsister TRUE TRUE FALSE - mtn_clan,Imperial - 1
mtn_clan TRUE TRUE FALSE - nightsister - 1
donkuwah_tribe TRUE TRUE FALSE - gondula_tribe,panshee_tribe - 1
gorax FALSE TRUE FALSE - gondula_tribe,panshee_tribe - 1
gondula_tribe TRUE TRUE FALSE - donkuwah_tribe,korga_tribe,pubam,endor_marauder panshee_tribe 1
korga_tribe TRUE TRUE FALSE - gondula_tribe,panshee_tribe - 1
endor_marauder TRUE TRUE FALSE - gondula_tribe,panshee_tribe - 1
panshee_tribe TRUE TRUE FALSE - donkuwah_tribe,korga_tribe,pubam,endor_marauder gondula_tribe 1
pubam TRUE TRUE FALSE - gondula_tribe,panshee_tribe - 1
bandit TRUE TRUE FALSE - townsperson - 1
pirate TRUE TRUE FALSE - - - 1
thug TRUE TRUE FALSE - townsperson - 1
townsperson TRUE FALSE FALSE - thug,bandit Rebel,Imperial 1
gungan TRUE TRUE FALSE - plasma_thief,swamp_rat,borvo - 1
naboo TRUE TRUE FALSE - borvo - 1
plasma_thief TRUE TRUE FALSE - gungan - 1
swamp_rat TRUE TRUE FALSE - gungan - 1
naboo_security_force TRUE TRUE FALSE - borvo,naboo_pirate,plasma_thief,swamp_rat,trade_federation - 1
naboo_pirate TRUE TRUE FALSE - naboo_security_force - 1
trade_federation TRUE TRUE FALSE - borvo,naboo_security_force - 1
aakuans TRUE TRUE FALSE - fed_dub,binayre,liberation_party - 1
fed_dub TRUE TRUE FALSE - liberation_party,binayre,lost_aqualish,drall - 1
binayre TRUE TRUE FALSE - fed_dub,aakuans,corsec - 1
liberation_party TRUE TRUE FALSE - fed_dub,corsec - 1
jabba TRUE TRUE FALSE - valarian,borvo Hutt 1
alkhara TRUE TRUE FALSE - tusken_raider - 1
desert_demon TRUE TRUE FALSE - swoop - 1
jawa TRUE TRUE FALSE - tusken_raider - 1
swoop TRUE TRUE FALSE - desert_demon - 1
tusken_raider TRUE TRUE FALSE - jawa,alkhara - 1
valarian TRUE TRUE FALSE - jabba - 1
drall TRUE TRUE FALSE - corsec,fed_dub - 1
borvo TRUE TRUE FALSE - gungan,trade_federation,jabba - 1
sif TRUE TRUE FALSE - Rebel,Imperial Hutt 1
flail TRUE TRUE FALSE - hidden_daggers - 1
cor_swoop TRUE TRUE FALSE - smashball - 1
restuss TRUE TRUE FALSE - garyn,cobral narmle 1
narmle TRUE TRUE FALSE - spice_collective,kobola restuss 1
rorgungan TRUE TRUE FALSE - spice_collective - 1
garyn TRUE TRUE FALSE - restuss - 1
cobral TRUE TRUE FALSE - restuss - 1
spice_collective TRUE TRUE FALSE - narmle,rorgungan,kobola - 1
kobola TRUE TRUE FALSE - narmle,spice_collective - 1
lost_aqualish TRUE TRUE FALSE - beldonnas_league,fed_dub,corsec - 1
spider_nightsister TRUE TRUE FALSE - mtn_clan - 1
bloodrazor TRUE TRUE FALSE - canyon_corsair,nym - 1
canyon_corsair TRUE TRUE FALSE - bloodrazor,nym - 1
lok_mercenaries TRUE TRUE FALSE - bloodrazor,canyon_corsair - 1
nym TRUE TRUE FALSE - bloodrazor,canyon_corsair,sulfur_lake_pirate - 1
warren_imperial FALSE TRUE FALSE - warren_huurton,warren_teraud,warren_cyborg warren_imperial_worker 1
warren_imperial_worker FALSE TRUE FALSE - warren_huurton,warren_teraud,warren_cyborg warren_imperial 1
warren_teraud FALSE TRUE FALSE - warren_huurton,warren_imperial,warren_imperial_worker,warren_cyborg,warren_scientist - 1
warren_huurton FALSE TRUE FALSE - warren_imperial,warren_imperial_worker,warren_cyborg,warren_teraud - 1
warren_cyborg FALSE TRUE FALSE - warren_imperial,warren_imperial_worker,warren_huurton,warren_teraud,warren_scientist - 1
warren_scientist FALSE TRUE FALSE - warren_teraud,warren_cyborg - 1
geonosian_mad_bunker FALSE TRUE FALSE - - geonosian_crazed_monster 1
geonosian_crazed_monster FALSE TRUE FALSE - - geonosian_mad_bunker 1
geonosian_crazy FALSE TRUE FALSE - geonosian_mad_bunker,geonosian_crazed_monster - 1
aggro_corsec FALSE TRUE FALSE - afarathu,followers_of_lord_nyax,monumenter,rogue_corsec,lost_aqualish corsec 1
death_watch FALSE TRUE FALSE - death_watch_special - 1
death_watch_special FALSE FALSE FALSE - - - 1
sith_shadow TRUE TRUE FALSE - fs_villager Rebel,Imperial 0
fs_villager TRUE TRUE FALSE - sith_shadow - 0
sith_shadow_nonaggro TRUE FALSE FALSE - fs_villager Rebel,Imperial 0
forest_outcast TRUE TRUE FALSE - forest_kerritamba - 1
forest_kerritamba TRUE TRUE FALSE - forest_outcast - 1
avatar_kashyyyk FALSE TRUE FALSE - avatar_blackscale - 1
avatar_blackscale FALSE TRUE FALSE - avatar_kashyyyk - 1
hsskor FALSE TRUE TRUE - kashyyyk_resistance - 1
kashyyyk_resistance FALSE TRUE TRUE - hsskor - 1
faction_sayormi FALSE TRUE FALSE - - - 1
yavin_scavenger TRUE TRUE FALSE - Hutt, jabba - 1
droid_army FALSE TRUE FALSE - mustafar_miners - 1
mustafar_miners FALSE TRUE FALSE - droid_army - 1
dark_jedi_kenobi FALSE TRUE FALSE - - - 1
underworld TRUE FALSE FALSE - - - 1
azure_cabal TRUE FALSE FALSE - - - 1
heroic_tusken FALSE TRUE FALSE - espa,expa_guard - 1
espa FALSE FALSE FALSE - - espa_guard 1
espa_guard FALSE TRUE FALSE - heroic_tusken espa 1
survivor FALSE FALSE FALSE - - - 1
afflicted FALSE TRUE FALSE - survivor,survivor_guard - 1
survivor_guard FALSE FALSE FALSE - afflicted - 1
sulfur_lake_pirate FALSE TRUE FALSE - nym - 1
@@ -0,0 +1,201 @@
STRUCTURE TEMP_STRUCTURE FOOTPRINT_TEMPLATE NO_LOT_REQUIREMENT LOT_REDUCTION EJECT_RANGE CIVIC CITY_RANK CITY_COST SHUTTLEPORT CLONE_FACILITY GARAGE CAN_RECLAIM MAINT_RATE DECAY_RATE CONDITION REDEED_COST HAS_SIGN POWER_RATE SKILLMOD SKILLMODVALUE SKILLMOD_MESSAGE OBJECT_1 X_1 Y_1 Z_1 CELL_1 HEADING_1 OBJECT_2 X_2 Y_2 Z_2 CELL_2 HEADING_2 OBJECT_3 X_3 Y_3 Z_3 CELL_3 HEADING_3 OBJECT_4 X_4 Y_4 Z_4 CELL_4 HEADING_4 OBJECT_5 X_5 Y_5 Z_5 CELL_5 HEADING_5 COMMENTS
TEXT TEXT TEXT TEXT INTEGER INTEGER TEXT INTEGER INTEGER TEXT TEXT TEXT TEXT INTEGER INTEGER INTEGER INTEGER INTEGER INTEGER TEXT INTEGER TEXT TEXT FLOAT FLOAT FLOAT TEXT INTEGER TEXT FLOAT FLOAT FLOAT TEXT INTEGER TEXT FLOAT FLOAT FLOAT TEXT INTEGER TEXT FLOAT FLOAT FLOAT TEXT INTEGER TEXT FLOAT FLOAT FLOAT TEXT INTEGER TEXT
object/building/player/player_house_tcg_relaxation_pool.iff object/building/player/construction/construction_player_tcg_relaxation_pool.iff none FALSE 4 32 FALSE 0 0 FALSE FALSE FALSE TRUE 9 4 5760 1700 1 0 - 0 - object/tangible/terminal/terminal_player_structure_nosnap.iff 7.25 4 0 entry -90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_jedi_meditation_room.iff object/building/player/construction/construction_player_jedi_meditation_room.iff none FALSE 2 32 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure_nosnap.iff 8.2 4 -1.1 entry -91 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_sith_meditation_room.iff object/building/player/construction/construction_player_sith_meditation_room.iff none FALSE 2 32 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure_nosnap.iff 4 4 1.85 entry 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_corellia_small_style_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -5 0.74 -2.76 entry -90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_corellia_small_style_01_floorplan_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -5 0.74 -1.81 entry -90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_corellia_small_style_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -6.5 0.63 3.77 entry 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_corellia_small_style_02_floorplan_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -6.7 0.62 3.55 entry 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_corellia_medium_style_01.iff object/building/player/construction/construction_player_house_tatooine_medium_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 9 4 5760 1700 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 3 0.62 06.04.2015 public 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_corellia_medium_style_02.iff object/building/player/construction/construction_player_house_tatooine_medium_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 9 4 5760 1700 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 3.5 1.76 -2.87 lobby -90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_corellia_large_style_01.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 3.17 4.59 -4.4 mainhall1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_corellia_large_style_02.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -6.22 4.71 -3.85 hallway 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_generic_small_style_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -5 0.74 -2.76 entry -90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_generic_small_style_01_floorplan_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -5 0.74 -1.81 entry -90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_generic_small_style_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -6.5 0.63 3.77 entry 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_generic_small_style_02_floorplan_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -6.69 0.62 3.55 entry 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_generic_medium_style_01.iff object/building/player/construction/construction_player_house_tatooine_medium_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 9 4 5760 1700 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 3 0.62 06.04.2015 public 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_generic_medium_style_02.iff object/building/player/construction/construction_player_house_tatooine_medium_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 9 4 5760 1700 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -7.15 0.88 5.59 middleroom 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_generic_large_style_01.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 3.17 4.59 -4.4 mainhall1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_generic_large_style_02.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -6.22 4.71 -3.85 hallway 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_naboo_small_style_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 3.1 0.7 5.31 foyer -90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_naboo_small_style_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 0.6 0.7 6.15 hall 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_naboo_medium_style_01.iff object/building/player/construction/construction_player_house_tatooine_medium_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 9 4 5760 1700 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 9.89 1.1 -10.75 foyerdown 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_naboo_medium_style_02.iff object/building/player/construction/construction_player_house_tatooine_medium_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 9 4 5760 1700 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 5.62 1.06 7.98 foyer 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_naboo_large_style_01.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 14.85 4.7 -1.76 hall1 -90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_tatooine_small_style_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 3.79 1.06 06.02.2015 foyer 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_tatooine_small_style_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 3.79 1.06 06.02.2015 foyer 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_tatooine_medium_style_01.iff object/building/player/construction/construction_player_house_tatooine_medium_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 9 4 5760 1700 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 6.94 1.06 7.98 foyer 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_tatooine_large_style_01.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 8.16 1.06 11.24 public 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/manufacture/clothing_factory.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 6 1000 2500 0 50 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/manufacture/food_factory.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 6 1000 2500 0 50 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/manufacture/weapon_factory.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 6 1000 2500 0 50 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/manufacture/structure_factory.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 6 1000 2500 0 50 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/generators/power_generator_fusion_style_1.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 15 6 1000 3000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/generators/power_generator_photo_bio_style_1.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 15 6 1000 3000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/generators/power_generator_solar_style_1.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 15 6 1000 3000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/generators/power_generator_geothermal_style_1.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 15 6 1000 3000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/generators/power_generator_wind_style_1.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 15 6 1000 3000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_gas/mining_gas_harvester_style_1.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 8 6 1000 1500 0 25 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_gas/mining_gas_harvester_style_2.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 15 6 1000 3000 0 50 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_gas/mining_gas_harvester_style_3.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 23 6 1000 4500 0 75 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_gas/mining_gas_harvester_style_4.iff object/installation/base/construction_installation_base.iff none FALSE 3 0 FALSE 0 0 FALSE FALSE FALSE TRUE 63 6 1000 12375 0 206 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_liquid/mining_liquid_harvester_style_1.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 8 6 1000 1500 0 25 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_liquid/mining_liquid_harvester_style_2.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 15 6 1000 3000 0 50 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_liquid/mining_liquid_harvester_style_3.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 23 6 1000 4500 0 75 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_liquid/mining_liquid_harvester_style_4.iff object/installation/base/construction_installation_base.iff none FALSE 3 0 FALSE 0 0 FALSE FALSE FALSE TRUE 63 6 1000 12375 0 206 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_liquid/mining_liquid_moisture_harvester.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 8 6 1000 1500 0 25 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_liquid/mining_liquid_moisture_harvester_medium.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 15 6 1000 3000 0 50 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_liquid/mining_liquid_moisture_harvester_heavy.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 23 6 1000 4500 0 75 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_liquid/mining_liquid_moisture_harvester_elite.iff object/installation/base/construction_installation_base.iff none FALSE 3 0 FALSE 0 0 FALSE FALSE FALSE TRUE 63 6 1000 12375 0 206 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_ore/mining_ore_harvester_style_1.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 8 6 1000 1500 0 25 - 20 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_ore/mining_ore_harvester_style_2.iff object/installation/mining_ore/construction/construction_mining_ore_harvester_style_2.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 15 6 1000 3000 0 50 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_ore/mining_ore_harvester_heavy.iff object/installation/mining_ore/construction/construction_mining_ore_harvester_style_heavy.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 23 6 1000 4500 0 75 - 10 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_ore/mining_ore_harvester_elite.iff object/installation/mining_ore/construction/construction_mining_ore_harvester_style_heavy.iff none FALSE 3 0 FALSE 0 0 FALSE FALSE FALSE TRUE 63 6 1000 12375 0 206 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_organic/mining_organic_creature_farm.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 6 1000 2500 0 50 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_organic/mining_organic_flora_farm.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 8 6 1000 1500 0 25 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_organic/mining_organic_flora_farm_medium.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 15 6 1000 3000 0 50 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_organic/mining_organic_flora_farm_heavy.iff object/installation/base/construction_installation_base.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 23 6 1000 4500 0 75 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/mining_organic/mining_organic_flora_farm_elite.iff object/installation/base/construction_installation_base.iff none FALSE 3 0 FALSE 0 0 FALSE FALSE FALSE TRUE 63 6 1000 12375 0 206 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_guildhall_corellia_style_01.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 0 0 FALSE FALSE FALSE TRUE 25 5 7200 5000 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 17.88 2.25 10.45 closeta 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_guildhall_generic_style_01.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 0 0 FALSE FALSE FALSE TRUE 25 5 7200 5000 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 17.88 2.25 10.45 closeta 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_guildhall_naboo_style_01.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 0 0 FALSE FALSE FALSE TRUE 25 5 7200 5000 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 17.88 2.25 10.45 closeta 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_guildhall_tatooine_style_01.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 0 0 FALSE FALSE FALSE TRUE 25 5 7200 5000 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 8.16 1.06 11.24 public 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_guildhall_tatooine_style_02.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 0 0 FALSE FALSE FALSE TRUE 25 5 7200 5000 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 9.13 1 6.36 lobby 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/turret/turret_block_large.iff object/installation/base/construction_installation_base.iff none FALSE 0 0 FALSE 0 0 FALSE FALSE FALSE FALSE 15 6 3000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/turret/turret_block_med.iff object/installation/base/construction_installation_base.iff none FALSE 0 0 FALSE 0 0 FALSE FALSE FALSE FALSE 10 6 2000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/turret/turret_block_sm.iff object/installation/base/construction_installation_base.iff none FALSE 0 0 FALSE 0 0 FALSE FALSE FALSE FALSE 5 6 1000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/faction_perk/covert_detector/detector_32m.iff object/installation/base/construction_installation_base.iff none FALSE 0 0 FALSE 0 0 FALSE FALSE FALSE FALSE 8 6 10000 1500 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/faction_perk/turret/block_lg.iff object/installation/base/construction_installation_base.iff none FALSE 0 0 FALSE 0 0 FALSE FALSE FALSE FALSE 15 6 300000 3000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/faction_perk/turret/block_med.iff object/installation/base/construction_installation_base.iff none FALSE 0 0 FALSE 0 0 FALSE FALSE FALSE FALSE 10 6 200000 2000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/faction_perk/turret/block_sm.iff object/installation/base/construction_installation_base.iff none FALSE 0 0 FALSE 0 0 FALSE FALSE FALSE FALSE 5 6 75000 1000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/faction_perk/turret/dish_sm.iff object/installation/base/construction_installation_base.iff none FALSE 0 0 FALSE 0 0 FALSE FALSE FALSE FALSE 5 6 75000 1000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/faction_perk/turret/dish_lg.iff object/installation/base/construction_installation_base.iff none FALSE 0 0 FALSE 0 0 FALSE FALSE FALSE FALSE 15 6 300000 3000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/faction_perk/turret/tower_lg.iff object/installation/base/construction_installation_base.iff none FALSE 0 0 FALSE 0 0 FALSE FALSE FALSE FALSE 15 6 300000 3000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/faction_perk/turret/tower_med.iff object/installation/base/construction_installation_base.iff none FALSE 0 0 FALSE 0 0 FALSE FALSE FALSE FALSE 10 6 200000 2000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/faction_perk/turret/tower_sm.iff object/installation/base/construction_installation_base.iff none FALSE 0 0 FALSE 0 0 FALSE FALSE FALSE FALSE 5 6 75000 1000 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/installation/faction_perk/minefield/field_1x1.iff object/installation/base/construction_installation_base.iff none FALSE 0 0 FALSE 0 0 FALSE FALSE FALSE FALSE 0 0 1000 0 0 0 - 0 - - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s01_rebel.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s01_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_rebel.iff 0 0 -6 mainhall 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s01_imp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s01_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_imperial.iff 0 0 -6 mainhall 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s02_rebel.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s02_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_rebel.iff 0 0.25 1.86 hall1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s02_imp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s02_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_imperial.iff 0 0.25 1.86 hall1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s03_rebel.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s03_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_rebel.iff 0 0.25 1.86 hall1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s03_imp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s03_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_imperial.iff 0 0.25 1.86 hall1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s04_rebel.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s04_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_rebel.iff 0 0.25 1.86 hall1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s04_imp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s04_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_imperial.iff 0 0.25 1.86 hall1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s05_rebel.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s05_fp.iff TRUE 0 32 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_rebel.iff 0 1 12.05.2015 mainhall 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s05_imp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s05_fp.iff TRUE 0 32 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_imperial.iff 0 1 12.05.2015 mainhall 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_merchant_tent_style_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 3 3 4320 600 1 0 private_place_merchant_tent 100 place_merchant_tent object/tangible/terminal/terminal_player_structure.iff -0.15 0.27 -2.76 r1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_merchant_tent_style_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 3 3 4320 600 1 0 private_place_merchant_tent 100 place_merchant_tent object/tangible/terminal/terminal_player_structure.iff -0.15 0.27 -2.76 r1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_merchant_tent_style_03.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 3 3 4320 600 1 0 private_place_merchant_tent 100 place_merchant_tent object/tangible/terminal/terminal_player_structure.iff -0.15 0.27 -2.76 r1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/cityhall_tatooine.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none TRUE 0 0 TRUE 0 1 FALSE FALSE FALSE FALSE 0 0 1000 0 1 0 private_place_cityhall 100 place_cityhall object/tangible/terminal/terminal_player_structure.iff -16.78 2 07.09.2015 mayoroffice 180 object/tangible/terminal/terminal_city_vote.iff 0.25 2 -9.65 grandhall 0 object/tangible/terminal/terminal_city.iff 17.07 2 -8.7 library 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/cityhall_naboo.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none TRUE 0 0 TRUE 0 1 FALSE FALSE FALSE FALSE 0 0 1000 0 1 0 private_place_cityhall 100 place_cityhall object/tangible/terminal/terminal_player_structure.iff -16.78 2 07.09.2015 mayoroffice 180 object/tangible/terminal/terminal_city_vote.iff 0.25 2 -9.65 grandhall 0 object/tangible/terminal/terminal_city.iff 17.07 2 -8.7 library 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/cityhall_corellia.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none TRUE 0 0 TRUE 0 1 FALSE FALSE FALSE FALSE 0 0 1000 0 1 0 private_place_cityhall 100 place_cityhall object/tangible/terminal/terminal_player_structure.iff -16.78 2 07.09.2015 mayoroffice 180 object/tangible/terminal/terminal_city_vote.iff 0.25 2 -9.65 grandhall 0 object/tangible/terminal/terminal_city.iff 17.07 2 -8.7 library 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/bank_tatooine.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none TRUE 0 0 TRUE 2 4 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_bank 100 place_bank object/tangible/terminal/terminal_bank.iff -1 -0.25 0 world 90 object/tangible/terminal/terminal_bank.iff 1 -0.25 0 world -90 object/tangible/terminal/terminal_bank.iff 0 -0.25 -1 world 0 object/tangible/terminal/terminal_player_structure_nosnap.iff 0 -0.25 1 world 180 - 0 0 0 - 0 -
object/building/player/city/bank_naboo.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none TRUE 0 0 TRUE 2 4 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_bank 100 place_bank object/tangible/terminal/terminal_bank.iff -1 -0.25 0 world 90 object/tangible/terminal/terminal_bank.iff 1 -0.25 0 world -90 object/tangible/terminal/terminal_bank.iff 0 -0.25 -1 world 0 object/tangible/terminal/terminal_player_structure_nosnap.iff 0 -0.25 1 world 180 - 0 0 0 - 0 -
object/building/player/city/bank_corellia.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none TRUE 0 0 TRUE 2 4 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_bank 100 place_bank object/tangible/terminal/terminal_bank.iff -1 -0.25 0 world 90 object/tangible/terminal/terminal_bank.iff 1 -0.25 0 world -90 object/tangible/terminal/terminal_bank.iff 0 -0.25 -1 world 0 object/tangible/terminal/terminal_player_structure_nosnap.iff 0 -0.25 1 world 180 - 0 0 0 - 0 -
object/building/player/city/barn_no_planet_restriction.iff object/building/player/construction/construction_player_barn.iff none FALSE 1 32 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure_nosnap.iff 3 1.8 3 entry 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/cantina_tatooine.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 2 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 private_place_cantina 100 place_cantina object/tangible/terminal/terminal_player_structure.iff -4.1 2 6.19 cantina 157 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/cantina_naboo.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 2 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 private_place_cantina 100 place_cantina object/tangible/terminal/terminal_player_structure.iff -4.1 2 6.19 cantina 157 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/cantina_corellia.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 2 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 private_place_cantina 100 place_cantina object/tangible/terminal/terminal_player_structure.iff -4.1 2 6.19 cantina 157 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/cloning_tatooine.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none TRUE 0 0 TRUE 3 3 FALSE TRUE FALSE TRUE 0 0 1000 0 1 0 private_place_cloning 100 place_cloning object/tangible/terminal/terminal_player_structure.iff -13.5 1 -6.4 cloninglab 90 object/tangible/terminal/terminal_cloning.iff -14 1 03.01.2015 cloninglab 90 object/tangible/terminal/terminal_insurance.iff 6.3 1 -6.69 cloninglab -90 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/cloning_corellia.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none TRUE 0 0 TRUE 3 3 FALSE TRUE FALSE TRUE 0 0 1000 0 1 0 private_place_cloning 100 place_cloning object/tangible/terminal/terminal_player_structure.iff -13.5 1 -6.4 cloninglab 90 object/tangible/terminal/terminal_cloning.iff -14 1 03.01.2015 cloninglab 90 object/tangible/terminal/terminal_insurance.iff 6.3 1 -6.69 cloninglab -90 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/cloning_naboo.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none TRUE 0 0 TRUE 3 3 FALSE TRUE FALSE TRUE 0 0 1000 0 1 0 private_place_cloning 100 place_cloning object/tangible/terminal/terminal_player_structure.iff -13.5 1 -6.4 cloninglab 90 object/tangible/terminal/terminal_cloning.iff -14 1 03.01.2015 cloninglab 90 object/tangible/terminal/terminal_insurance.iff 6.3 1 -6.69 cloninglab -90 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/diner_no_planet_restriction.iff object/building/player/construction/construction_player_diner.iff none FALSE 1 32 FALSE 3 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure_nosnap.iff 8.8 1.1 1.73 entry -91 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/hospital_tatooine.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 3 0 FALSE 3 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 private_place_hospital 100 place_hospital object/tangible/terminal/terminal_player_structure.iff 7.48 2 01.05.2015 mainroom -90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/hospital_corellia.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 3 0 FALSE 3 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 private_place_hospital 100 place_hospital object/tangible/terminal/terminal_player_structure.iff 7.48 2 01.05.2015 mainroom -90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/hospital_naboo.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 3 0 FALSE 3 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 private_place_hospital 100 place_hospital object/tangible/terminal/terminal_player_structure.iff 7.48 2 01.05.2015 mainroom -90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/theater_tatooine.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 3 0 FALSE 4 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 private_place_theater 100 place_theater object/tangible/terminal/terminal_player_structure.iff -7 2 -14.2 backstage 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/theater_naboo.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 3 0 FALSE 4 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 private_place_theater 100 place_theater object/tangible/terminal/terminal_player_structure.iff -7 2 -14.2 backstage 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/theater_corellia.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 3 0 FALSE 4 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 private_place_theater 100 place_theater object/tangible/terminal/terminal_player_structure.iff -7 2 -14.2 backstage 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/shuttleport_tatooine.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none TRUE 0 0 TRUE 4 2 TRUE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_shuttleport 100 place_shuttleport object/tangible/terminal/terminal_player_structure_nosnap.iff 8.4 -1 -14.5 world 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/shuttleport_naboo.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none TRUE 0 0 TRUE 4 2 TRUE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_shuttleport 100 place_shuttleport object/tangible/terminal/terminal_player_structure_nosnap.iff 8.4 -1 -14.5 world 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/shuttleport_corellia.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none TRUE 0 0 TRUE 4 2 TRUE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_shuttleport 100 place_shuttleport object/tangible/terminal/terminal_player_structure_nosnap.iff 8.4 -1 -14.5 world 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_lrg_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_lrg_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_lrg_03.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_lrg_04.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_lrg_05.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_med_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_med_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_med_03.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_med_04.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_med_05.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_sml_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_sml_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_sml_03.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_sml_04.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_corellia_sml_05.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_lrg_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_lrg_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_lrg_03.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_lrg_04.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_lrg_05.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_med_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_med_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_med_03.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_med_04.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_med_05.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_sml_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_sml_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_sml_03.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_sml_04.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_naboo_sml_05.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_lrg_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_lrg_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_lrg_03.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_lrg_04.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_lrg_05.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_large_garden 100 place_large_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_med_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_med_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_med_03.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_med_04.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_med_05.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_medium_garden 100 place_medium_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_sml_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_sml_02.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_sml_03.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_sml_04.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_tatooine_sml_05.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_dantooine_lrg_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_exotic_garden 100 place_exotic_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_dantooine_med_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_exotic_garden 100 place_exotic_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_dantooine_sml_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_exotic_garden 100 place_exotic_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_dathomir_lrg_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_exotic_garden 100 place_exotic_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_dathomir_med_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_exotic_garden 100 place_exotic_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_dathomir_sml_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_exotic_garden 100 place_exotic_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_endor_lrg_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 3 6 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_exotic_garden 100 place_exotic_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 12 -1 -12 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_endor_med_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_exotic_garden 100 place_exotic_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 8 -1 -8 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_endor_sml_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_exotic_garden 100 place_exotic_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 4.5 -1 -4.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_garage_tatooine_style_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE TRUE TRUE 0 0 1000 0 0 0 private_place_garage 100 place_garage object/tangible/terminal/terminal_player_structure_nosnap_mini.iff -3 -1 -3 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_garage_naboo_style_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE TRUE TRUE 0 0 1000 0 0 0 private_place_garage 100 place_garage object/tangible/terminal/terminal_player_structure_nosnap_mini.iff -3 -1 -3 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_garage_corellia_style_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 2 3 FALSE FALSE TRUE TRUE 0 0 1000 0 0 0 private_place_garage 100 place_garage object/tangible/terminal/terminal_player_structure_nosnap_mini.iff -3 -1 -3 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s01_rebel_pvp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s01_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_rebel.iff 0 0 -6 mainhall 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s01_imp_pvp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s01_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_imperial.iff 0 0 -6 mainhall 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s02_rebel_pvp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s02_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_rebel.iff 0 0.25 1.86 hall1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s02_imp_pvp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s02_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_imperial.iff 0 0.25 1.86 hall1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s03_rebel_pvp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s03_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_rebel.iff 0 0.25 1.86 hall1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s03_imp_pvp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s03_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_imperial.iff 0 0.25 1.86 hall1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s04_rebel_pvp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s04_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_rebel.iff 0 0.25 1.86 hall1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s04_imp_pvp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s04_fp.iff TRUE 0 8 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_imperial.iff 0 0.25 1.86 hall1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s05_rebel_pvp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s05_fp.iff TRUE 0 32 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_rebel.iff 0 1 12.05.2015 mainhall 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/faction_perk/hq/hq_s05_imp_pvp.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff object/building/faction_perk/hq/hq_s05_fp.iff TRUE 0 32 FALSE 0 0 FALSE FALSE FALSE FALSE 0 200 100000 0 1 0 - 0 - object/tangible/terminal/terminal_hq_imperial.iff 0 1 12.05.2015 mainhall 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_mustafar_lg.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 8 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 0 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -4.5 0.46 6.33 entrance 90 object/tangible/terminal/terminal_elevator_up.iff -1.19 -33 1.61 elevator 160 object/tangible/terminal/terminal_elevator_down.iff 1.18 -26 1.65 elevator -166 object/tangible/terminal/terminal_elevator_down.iff 1.18 0.47 1.65 elevator -166 - 0 0 0 - 0 -
object/building/player/city/garden_imperial_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 1.5 -0.9 -3.5 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/city/garden_rebel_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none TRUE 0 0 TRUE 1 5 FALSE FALSE FALSE TRUE 0 0 1000 0 1 0 private_place_small_garden 100 place_small_garden object/tangible/terminal/terminal_player_structure_nosnap_mini.iff 2.85 -0.9 -4 world 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_tatooine_small_window_style_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 3.79 1.06 06.02.2015 foyer 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_naboo_small_window_style_01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 3.1 0.7 5.31 foyer -90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_generic_small_windowed.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -5 0.74 -1.81 entry -90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_generic_medium_windowed.iff object/building/player/construction/construction_player_house_tatooine_medium_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 9 4 5760 1700 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 5 0.62 06.04.2015 public -180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_generic_small_window_style_03.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -1.8 3 04.03.2015 entry -180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_generic_medium_windowed_s02.iff object/building/player/construction/construction_player_house_tatooine_medium_style_01.iff none FALSE 2 0 FALSE 0 0 FALSE FALSE FALSE TRUE 9 4 5760 1700 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 5 -2 6 entryway -180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_generic_large_window_s01.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -6.22 4.71 -3.85 hallway 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 Z = FORWARD/BACK /// Y = UP/DOWN
object/building/player/player_house_generic_large_window_s02.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 5 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 8 0 -8.5 entry 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 X = right/left /// Y = UP/DOWN
object/building/player/player_house_hangar.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 3 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 0 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 8.9 0 -6.5 entry -90 object/tangible/terminal/terminal_player_hangar_structure.iff 8.9 0 -12.6 entry -90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 X = right/left
object/building/player/player_house_atat.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 3 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 3.8 1.06 10.05.2015 body 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_tcg_emperors_spire.iff object/building/player/construction/construction_player_tcg_emperors_spire.iff none FALSE 2 32 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure_nosnap.iff -2.6 25.6 0 tower -91 object/tangible/terminal/terminal_elevator_up.iff -0.76 1.69 -1.1 elevator 0 object/tangible/terminal/terminal_elevator_down.iff 0.74 26.7 -1.1 elevator 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_tcg_rebel_spire.iff object/building/player/construction/construction_player_tcg_rebel_spire.iff none FALSE 2 32 FALSE 0 0 FALSE FALSE FALSE TRUE 4 3 4320 800 1 0 - 0 - object/tangible/terminal/terminal_player_structure_nosnap.iff -1.24 25.4 -1.59 tower 180 object/tangible/terminal/terminal_elevator_up.iff -0.75 1.59 -1.1 elevator 0 object/tangible/terminal/terminal_elevator_down.iff 0.74 25.1 -1.1 elevator 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_sandcrawler.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 3 0 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 2500 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -4.46 8.81 -13.52 foyer 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_pgc_merchant_tent_s01.iff object/building/player/construction/construction_player_house_tatooine_small_style_01.iff none FALSE 1 0 FALSE 0 0 FALSE FALSE FALSE TRUE 3 3 4320 600 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -0.15 0.27 -2.76 r1 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_tcg_commando_bunker.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 2 8 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 0 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 3.2 0.4 3.16 entry 180 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_tcg_vehicle_garage.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 2 8 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 0 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff 14.56 0.53 12.79 entry 180 object/tangible/terminal/terminal_player_vehicle_garage.iff -1.1 0.84 -9.95 entry 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
object/building/player/player_house_tcg_vip_bunker.iff object/building/player/construction/construction_player_house_tatooine_large_style_01.iff none FALSE 2 8 FALSE 0 0 FALSE FALSE FALSE TRUE 13 5 7200 0 1 0 - 0 - object/tangible/terminal/terminal_player_structure.iff -4.5 0.46 6.33 entrance 90 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 - 0 0 0 - 0 -
File diff suppressed because it is too large Load Diff
+6455 -6289
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -34,7 +34,7 @@ naboo starport Moenia Starport 4745 4 -4672
naboo shuttleport Theed Shuttle A -5856 6 4172
naboo shuttleport Theed Shuttle B -5005 6 4072
naboo shuttleport Theed Shuttle C -5411 6 4321
naboo starport Theed Spaceport -4866 6 4155
naboo theed_starport Theed Spaceport -4866 6 4155
rori starport Narmle Starport -5359 80 -2188
rori shuttleport Narmle Shuttleport -5255 80 -2161
rori starport Rebel Outpost 3693 96 -6403
-11
View File
@@ -27,7 +27,6 @@
***********************************************************************************/
package intents;
import resources.Galaxy;
import resources.control.Intent;
import services.galaxy.GalacticManager;
import services.objects.ObjectManager;
@@ -36,7 +35,6 @@ import services.player.PlayerManager;
public abstract class GalacticIntent extends Intent {
private GalacticManager galacticManager;
private Galaxy galaxy;
protected GalacticIntent(String type) {
super(type);
@@ -45,17 +43,12 @@ public abstract class GalacticIntent extends Intent {
protected GalacticIntent(GalacticIntent i) {
super(i.getType());
setGalacticManager(i.getGalacticManager());
setGalaxy(i.getGalaxy());
}
public void setGalacticManager(GalacticManager galacticManager) {
this.galacticManager = galacticManager;
}
public void setGalaxy(Galaxy galaxy) {
this.galaxy = galaxy;
}
public ObjectManager getObjectManager() {
return galacticManager.getObjectManager();
}
@@ -68,8 +61,4 @@ public abstract class GalacticIntent extends Intent {
return galacticManager;
}
public Galaxy getGalaxy() {
return galaxy;
}
}
-9
View File
@@ -37,7 +37,6 @@ public class PlayerEventIntent extends Intent {
private Player player;
private PlayerEvent event;
private String galaxy;
public PlayerEventIntent(Player p, PlayerEvent event) {
super(TYPE);
@@ -45,11 +44,6 @@ public class PlayerEventIntent extends Intent {
setEvent(event);
}
public PlayerEventIntent(Player p, String galaxy, PlayerEvent event) {
this(p, event);
this.galaxy = galaxy;
}
public void setPlayer(Player p) {
this.player = p;
}
@@ -66,7 +60,4 @@ public class PlayerEventIntent extends Intent {
return event;
}
public String getGalaxy() {
return galaxy;
}
}
+7 -7
View File
@@ -37,13 +37,13 @@ public class RequestZoneInIntent extends Intent {
private Player player;
private CreatureObject creature;
private String galaxy;
private boolean firstZone;
public RequestZoneInIntent(Player player, CreatureObject creature, String galaxy) {
public RequestZoneInIntent(Player player, CreatureObject creature, boolean firstZone) {
super(TYPE);
setPlayer(player);
setCreature(creature);
setGalaxy(galaxy);
setFirstZone(firstZone);
}
public void setPlayer(Player player) {
@@ -54,8 +54,8 @@ public class RequestZoneInIntent extends Intent {
this.creature = creature;
}
public void setGalaxy(String galaxy) {
this.galaxy = galaxy;
public void setFirstZone(boolean firstZone) {
this.firstZone = firstZone;
}
public Player getPlayer() {
@@ -66,8 +66,8 @@ public class RequestZoneInIntent extends Intent {
return creature;
}
public String getGalaxy() {
return galaxy;
public boolean isFirstZone() {
return firstZone;
}
}
+5 -15
View File
@@ -27,46 +27,36 @@
***********************************************************************************/
package intents.network;
import network.packets.soe.Disconnect.DisconnectReason;
import resources.control.Intent;
import resources.network.DisconnectReason;
public class CloseConnectionIntent extends Intent {
public static final String TYPE = "CloseConnectionIntent";
private int connId;
private long networkId;
private DisconnectReason reason;
public CloseConnectionIntent(int connId, long networkId, DisconnectReason reason) {
public CloseConnectionIntent(long networkId, DisconnectReason reason) {
super(TYPE);
setConnectionId(connId);
setNetworkId(networkId);
setReason(reason);
}
public void setConnectionId(int connId) {
this.connId = connId;
setDisconnectReason(reason);
}
public void setNetworkId(long networkId) {
this.networkId = networkId;
}
public void setReason(DisconnectReason reason) {
public void setDisconnectReason(DisconnectReason reason) {
this.reason = reason;
}
public int getConnectionId() {
return connId;
}
public long getNetworkId() {
return networkId;
}
public DisconnectReason getReason() {
public DisconnectReason getDisconnectReason() {
return reason;
}
@@ -25,35 +25,39 @@
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package resources;
package intents.network;
import static org.junit.Assert.assertTrue;
import java.util.Iterator;
import org.junit.Test;
import resources.control.Intent;
import resources.network.DisconnectReason;
public class TestSortedLinkedList {
/**
* Characters are compared by numerical value and they
* should therefore be stored in such order within the list.
*/
@Test
public void testSorting() {
SortedLinkedList<Character> list = new SortedLinkedList<>();
final char testchar1 = 'a';
final char testchar2 = 'b';
final char testchar3 = 'c';
Iterator<Character> it;
list.add(testchar2);
list.add(testchar3);
list.add(testchar1);
it = list.listIterator();
assertTrue(it.next().equals(testchar1));
assertTrue(it.next().equals(testchar2));
assertTrue(it.next().equals(testchar3));
public class ConnectionClosedIntent extends Intent {
public static final String TYPE = "ConnectionClosedIntent";
private long networkId;
private DisconnectReason reason;
public ConnectionClosedIntent(long networkId, DisconnectReason reason) {
super(TYPE);
setNetworkId(networkId);
setReason(reason);
}
public void setNetworkId(long networkId) {
this.networkId = networkId;
}
public void setReason(DisconnectReason reason) {
this.reason = reason;
}
public long getNetworkId() {
return networkId;
}
public DisconnectReason getReason() {
return reason;
}
}
@@ -25,40 +25,28 @@
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package network.packets.soe;
package intents.network;
import java.nio.ByteBuffer;
import network.packets.Packet;
import resources.control.Intent;
public class OutOfOrder extends Packet {
public class ConnectionOpenedIntent extends Intent {
private short sequence;
public static final String TYPE = "ConnectionOpenedIntent";
public OutOfOrder() {
private long networkId;
public ConnectionOpenedIntent(long networkId) {
super(TYPE);
setNetworkId(networkId);
}
public OutOfOrder(short sequence) {
this.sequence = sequence;
public void setNetworkId(long networkId) {
this.networkId = networkId;
}
public OutOfOrder(ByteBuffer data) {
decode(data);
public long getNetworkId() {
return networkId;
}
public void decode(ByteBuffer data) {
data.position(2);
sequence = getNetShort(data);
}
public ByteBuffer encode() {
ByteBuffer data = ByteBuffer.allocate(4);
addNetShort(data, 0x11);
addNetShort(data, sequence);
return data;
}
public short getSequence() { return sequence; }
}
+13 -17
View File
@@ -27,8 +27,8 @@
***********************************************************************************/
package intents.network;
import network.packets.soe.Disconnect.DisconnectReason;
import resources.control.Intent;
import resources.network.DisconnectReason;
import resources.player.Player;
public class ForceDisconnectIntent extends Intent {
@@ -36,50 +36,46 @@ public class ForceDisconnectIntent extends Intent {
public static final String TYPE = "ForceDisconnectIntent";
private Player player;
private DisconnectReason reason;
private boolean disappearImmediately;
private DisconnectReason reason;
public ForceDisconnectIntent(Player player) {
this(player, false);
}
public ForceDisconnectIntent(Player player, DisconnectReason reason) {
this(player, reason, false);
}
public ForceDisconnectIntent(Player player, boolean disappearImmediately) {
this(player, DisconnectReason.APPLICATION, disappearImmediately);
this(player, disappearImmediately, DisconnectReason.APPLICATION);
}
public ForceDisconnectIntent(Player player, DisconnectReason reason, boolean disappearImmediately) {
public ForceDisconnectIntent(Player player, boolean disappearImmediately, DisconnectReason reason) {
super(TYPE);
setPlayer(player);
setDisconnectReason(reason);
setDisappearImmediately(disappearImmediately);
setDisconnectReason(reason);
}
public void setPlayer(Player player) {
this.player = player;
}
public void setDisconnectReason(DisconnectReason reason) {
this.reason = reason;
}
public void setDisappearImmediately(boolean disappearImmediately) {
this.disappearImmediately = disappearImmediately;
}
public void setDisconnectReason(DisconnectReason reason) {
this.reason = reason;
}
public Player getPlayer() {
return player;
}
public DisconnectReason getDisconnectReason() {
return reason;
}
public boolean getDisappearImmediately() {
return disappearImmediately;
}
public DisconnectReason getDisconnectReason() {
return reason;
}
}
+1 -13
View File
@@ -29,27 +29,23 @@ package intents.network;
import intents.GalacticIntent;
import network.packets.Packet;
import resources.network.ServerType;
public class GalacticPacketIntent extends GalacticIntent {
public static final String TYPE = "GalacticPacketIntent";
private Packet packet;
private ServerType type;
private long networkId;
public GalacticPacketIntent(InboundPacketIntent i) {
super(TYPE);
setPacket(i.getPacket());
setServerType(i.getServerType());
setNetworkId(i.getNetworkId());
}
public GalacticPacketIntent(ServerType type, Packet p, long networkId) {
public GalacticPacketIntent(Packet p, long networkId) {
super(TYPE);
setPacket(p);
setServerType(type);
setNetworkId(networkId);
}
@@ -57,10 +53,6 @@ public class GalacticPacketIntent extends GalacticIntent {
this.packet = p;
}
public void setServerType(ServerType type) {
this.type = type;
}
public void setNetworkId(long networkId) {
this.networkId = networkId;
}
@@ -69,10 +61,6 @@ public class GalacticPacketIntent extends GalacticIntent {
return packet;
}
public ServerType getServerType() {
return type;
}
public long getNetworkId() {
return networkId;
}
+1 -12
View File
@@ -29,20 +29,17 @@ package intents.network;
import network.packets.Packet;
import resources.control.Intent;
import resources.network.ServerType;
public class InboundPacketIntent extends Intent {
public static final String TYPE = "InboundPacketIntent";
private Packet packet;
private ServerType type;
private long networkId;
public InboundPacketIntent(ServerType type, Packet p, long networkId) {
public InboundPacketIntent(Packet p, long networkId) {
super(TYPE);
setPacket(p);
setServerType(type);
setNetworkId(networkId);
}
@@ -50,10 +47,6 @@ public class InboundPacketIntent extends Intent {
this.packet = p;
}
public void setServerType(ServerType type) {
this.type = type;
}
public void setNetworkId(long networkId) {
this.networkId = networkId;
}
@@ -62,10 +55,6 @@ public class InboundPacketIntent extends Intent {
return packet;
}
public ServerType getServerType() {
return type;
}
public long getNetworkId() {
return networkId;
}
@@ -1,51 +0,0 @@
/*******************************************************************************
* Copyright (c) 2015 /// 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 intents.object;
import resources.control.Intent;
import resources.objects.SWGObject;
/**
* Created by Waverunner on 8/19/2015
*/
public class ObjectCreateIntent extends Intent {
public static final String TYPE = "ObjectCreateIntent";
private SWGObject object;
public ObjectCreateIntent(SWGObject object) {
super(TYPE);
this.object = object;
}
public SWGObject getObject() {
return object;
}
}
@@ -1,54 +0,0 @@
/*******************************************************************************
* Copyright (c) 2015 /// 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 intents.object;
import resources.control.Intent;
/**
* Created by Waverunner on 8/19/2015
*/
public class ObjectIdRequestIntent extends Intent {
public static final String TYPE = "ObjectIdRequestIntent";
private String identifier;
private int amount;
public ObjectIdRequestIntent(String identifier, int amount) {
super(TYPE);
this.identifier = identifier;
this.amount = amount;
}
public String getIdentifier() {
return identifier;
}
public int getAmount() {
return amount;
}
}
@@ -1,56 +0,0 @@
/*******************************************************************************
* Copyright (c) 2015 /// 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 intents.object;
import resources.control.Intent;
import java.util.List;
/**
* Created by Waverunner on 8/19/2015
*/
public class ObjectIdResponseIntent extends Intent {
public static final String TYPE = "ObjectIdResponseIntent";
private String identifier;
private List<Long> reservedIds;
public ObjectIdResponseIntent(String identifier, List<Long> reservedIds) {
super(TYPE);
this.identifier = identifier;
this.reservedIds = reservedIds;
}
public String getIdentifier() {
return identifier;
}
public List<Long> getReservedIds() {
return reservedIds;
}
}
@@ -0,0 +1,34 @@
package intents.object;
import resources.control.Intent;
import resources.objects.SWGObject;
public class UpdateObjectAwareness extends Intent {
public static final String TYPE = "UpdateObjectAwareness";
private SWGObject object;
private boolean inAwareness;
public UpdateObjectAwareness(SWGObject object, boolean inAwareness) {
super(TYPE);
setObject(object);
}
public void setObject(SWGObject object) {
this.object = object;
}
public void setInAwareness(boolean inAwareness) {
this.inAwareness = inAwareness;
}
public SWGObject getObject() {
return object;
}
public boolean isInAwareness() {
return inAwareness;
}
}
@@ -0,0 +1,36 @@
package intents.radial;
import resources.control.Intent;
import resources.objects.SWGObject;
import resources.objects.creature.CreatureObject;
public class ObjectClickedIntent extends Intent {
public static final String TYPE = "ObjectClickedIntent";
private CreatureObject requestor;
private SWGObject target;
public ObjectClickedIntent(CreatureObject requestor, SWGObject target) {
super(TYPE);
setRequestor(requestor);
setTarget(target);
}
public void setRequestor(CreatureObject requestor) {
this.requestor = requestor;
}
public void setTarget(SWGObject target) {
this.target = target;
}
public CreatureObject getRequestor() {
return requestor;
}
public SWGObject getTarget() {
return target;
}
}
+19 -12
View File
@@ -31,6 +31,7 @@ import intents.server.ServerStatusIntent;
import resources.Galaxy.GalaxyStatus;
import resources.control.IntentManager;
import resources.control.ServerStatus;
import resources.server_info.Log;
import services.CoreManager;
public class ProjectSWG {
@@ -52,9 +53,13 @@ public class ProjectSWG {
server.run();
} catch (CoreException e) {
System.err.println("ProjectSWG: Shutting down. Reason: " + e.getMessage());
Log.e("CoreManager", "Shutting down. Reason: " + e.getMessage());
Log.e("CoreManager", e);
} catch (Exception e) {
e.printStackTrace();
System.err.println("ProjectSWG: Shutting down - unknown error.");
Log.e("CoreManager", "Shutting down - unknown error.");
Log.e("CoreManager", e);
}
server.stop();
server.terminate();
@@ -69,16 +74,6 @@ public class ProjectSWG {
return (long) server.manager.getCoreTime();
}
/**
* Returns the server's galaxy ID. This may be
* deprecated in the future if multiple servers are run
* at once.
* @return the server's galaxy ID
*/
public static final int getGalaxyId() {
return CoreManager.getGalaxyId();
}
/**
* Returns the server's galactic time. This is the official time sent to
* the client and should be used for any official client-time purposes.
@@ -98,6 +93,7 @@ public class ProjectSWG {
manager = new CoreManager();
long end = System.nanoTime();
System.out.println("ProjectSWG: Created new manager in " + (end-start)/1E6 + "ms");
Log.i(manager, "Created new manager in %.3fms", (end-start)/1E6);
while (!shutdownRequested && !manager.isShutdownRequested()) {
initialize();
start();
@@ -109,6 +105,7 @@ public class ProjectSWG {
manager = new CoreManager();
end = System.nanoTime();
System.out.println("ProjectSWG: Created new manager in " + (end-start)/1E6 + "ms");
Log.i(manager, "Created new manager in %.3fms", (end-start)/1E6);
}
}
}
@@ -127,22 +124,25 @@ public class ProjectSWG {
private void initialize() {
setStatus(ServerStatus.INITIALIZING);
System.out.println("ProjectSWG: Initializing...");
Log.i(manager, "Initializing...");
if (!manager.initialize())
throw new CoreException("Failed to initialize.");
System.out.println("ProjectSWG: Initialized. Time: " + manager.getCoreTime() + "ms");
Log.i(manager, "Initialized. Time: %.3fms", manager.getCoreTime());
}
private void start() {
System.out.println("ProjectSWG: Starting...");
Log.i(manager, "Starting...");
if (!manager.start())
throw new CoreException("Failed to start.");
System.out.println("ProjectSWG: Started. Time: " + manager.getCoreTime() + "ms");
Log.i(manager, "Started. Time: %.3fms", manager.getCoreTime());
}
private void loop() {
setStatus((manager.getGalaxyStatus() == GalaxyStatus.UP) ? ServerStatus.OPEN : ServerStatus.LOCKED);
while (!shutdownRequested && !manager.isShutdownRequested() && manager.isOperational()) {
manager.flushPackets(); // Sends any packets that weren't sent
try {
Thread.sleep(50);
} catch (InterruptedException e) {
@@ -155,30 +155,37 @@ public class ProjectSWG {
if (manager == null || status == ServerStatus.OFFLINE)
return;
System.out.println("ProjectSWG: Stopping...");
Log.i(manager, "Stopping...");
setStatus(ServerStatus.STOPPING);
if (!manager.stop())
if (!manager.stop()) {
System.err.println("Failed to stop.");
Log.e(manager, "Failed to stop.");
}
long intentWait = System.nanoTime();
while (IntentManager.getIntentsQueued() > 0 && System.nanoTime()-intentWait < 3E9) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.err.println("ProjectSWG: Failed to stop! Interrupted with " + IntentManager.getIntentsQueued() + " intents remaining");
Log.e(manager, "Failed to stop! Interrupted with %d intents remaining", IntentManager.getIntentsQueued());
break;
}
}
System.out.println("ProjectSWG: Stopped. Time: " + manager.getCoreTime() + "ms");
Log.i(manager, "Stopped. Time: %.3fms", manager.getCoreTime());
}
private void terminate() {
if (manager == null || status == ServerStatus.OFFLINE)
return;
System.out.println("ProjectSWG: Terminating...");
Log.i(manager, "Terminating...");
setStatus(ServerStatus.TERMINATING);
if (!manager.terminate())
throw new CoreException("Failed to terminate.");
setStatus(ServerStatus.OFFLINE);
System.out.println("ProjectSWG: Terminated. Time: " + manager.getCoreTime() + "ms");
Log.i(manager, "Terminated. Time: %.3fms", manager.getCoreTime());
}
public static class CoreException extends RuntimeException {
-111
View File
@@ -1,111 +0,0 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 network;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import network.packets.soe.Fragmented;
public class FragmentedHandler {
private List<Fragmented> fragPackets;
private int fragSize;
public FragmentedHandler() {
fragPackets = new ArrayList<Fragmented>();
fragSize = 0;
}
public void reset() {
fragPackets.clear();
fragSize = 0;
}
public byte [] onReceived(Fragmented f) {
synchronized (fragPackets) {
if (insertIfNew(f) && getBufferedSize() == fragSize) {
byte [] data = new byte[fragSize];
int offset = 0;
for (Fragmented frag : fragPackets) {
offset = spliceFragmentedIntoBuffer(frag, data, offset);
}
updateMetadata();
return data;
}
return new byte[0];
}
}
private boolean insertIfNew(Fragmented f) {
synchronized (fragPackets) {
if (!fragPackets.contains(f)) {
fragPackets.add(f);
updateMetadata();
return true;
}
}
return false;
}
private int spliceFragmentedIntoBuffer(Fragmented f, byte [] data, int offset) {
byte [] fData = f.encode().array();
int header = offset==0?8:4;
System.arraycopy(fData, header, data, offset, fData.length-header);
return offset + fData.length-header;
}
private void updateMetadata() {
synchronized (fragPackets) {
if (fragPackets.isEmpty())
fragSize = 0;
else
fragSize = fragPackets.get(0).encode().order(ByteOrder.BIG_ENDIAN).getInt(4);
}
}
private int getBufferedSize() {
int curSize = 0;
int i = 0;
short prevSeq = (short) (fragPackets.get(0).getSequence()-1);
for (Fragmented frag : fragPackets) {
// Update previous sequence and verify all in-order
if (prevSeq+1 != frag.getSequence())
break;
prevSeq = frag.getSequence();
// Update current size
curSize += (i == 0) ? frag.encode().array().length-8 : frag.encode().array().length-4;
i++;
if (curSize >= fragSize)
break;
}
return curSize;
}
}
-194
View File
@@ -1,194 +0,0 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 network;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.LinkedList;
import java.util.Queue;
import network.encryption.Encryption;
import network.packets.Packet;
import network.packets.soe.Acknowledge;
import network.packets.soe.ClientNetworkStatusUpdate;
import network.packets.soe.DataChannelA;
import network.packets.soe.Disconnect;
import network.packets.soe.Fragmented;
import network.packets.soe.MultiPacket;
import network.packets.soe.OutOfOrder;
import network.packets.soe.SessionRequest;
import network.packets.soe.SessionResponse;
import network.packets.swg.SWGPacket;
import network.packets.swg.zone.object_controller.ObjectController;
public class InboundNetworkHandler {
private final Queue <Packet> inboundQueue;
private final FragmentedHandler fragStream;
private final InboundEventCallback eventCallback;
private short recvSequence;
private int crc;
public InboundNetworkHandler(InboundEventCallback eventCallback) {
this.inboundQueue = new LinkedList<Packet>();
this.fragStream = new FragmentedHandler();
this.eventCallback = eventCallback;
recvSequence = -1;
crc = 0;
}
public synchronized void reset() {
fragStream.reset();
inboundQueue.clear();
recvSequence = -1;
crc = 0;
}
public synchronized void setCrc(int crc) {
this.crc = crc;
}
public synchronized int getCrc() {
return crc;
}
public synchronized short getReceivedSequence() {
return recvSequence;
}
public synchronized boolean hasInbound() {
synchronized (inboundQueue) {
return !inboundQueue.isEmpty();
}
}
public synchronized Packet pollInbound() {
synchronized (inboundQueue) {
return inboundQueue.poll();
}
}
private void pushPacket(Packet packet) {
synchronized (inboundQueue) {
inboundQueue.add(packet);
}
}
public synchronized int onReceive(byte [] data) {
if (data.length < 2)
return 0;
if (data[1] == 1 || data[1] == 2)
return processPacket(data);
else
return processPacket(Encryption.decode(data, crc));
}
private int processPacket(byte [] data) {
if (data.length < 2)
return 0;
ByteBuffer bb = ByteBuffer.wrap(data);
int packets = 0;
switch (data[1]) {
case 0x00:
if (data[0] > 0)
packets += processSwgPacket(data);
break;
case 0x01: ++packets; pushPacket(new SessionRequest(bb)); break;
case 0x02: ++packets; pushPacket(new SessionResponse(bb)); break;
case 0x03: packets += processMulti(new MultiPacket(bb)); break;
case 0x05: ++packets; pushPacket(new Disconnect(bb)); break;
case 0x07: ++packets; pushPacket(new ClientNetworkStatusUpdate(bb)); break;
case 0x09: packets += processData(new DataChannelA(bb)); break;
case 0x0D: packets += processFrag(new Fragmented(bb)); break;
case 0x11: ++packets; pushPacket(new OutOfOrder(bb)); break;
case 0x15: ++packets; pushPacket(new Acknowledge(bb)); break;
default:
break;
}
return packets;
}
private int processMulti(MultiPacket packet) {
int packets = 0;
for (Packet p : packet.getPackets())
packets += processPacket(p.getData().array());
return packets;
}
private int processData(DataChannelA packet) {
if (packet.getSequence() != (short) (recvSequence+1)) {
if (packet.getSequence() > recvSequence)
eventCallback.sendOutOfOrder(packet.getSequence());
return 0;
}
recvSequence = packet.getSequence();
eventCallback.sendAcknowledge(recvSequence);
int packets = 0;
for (SWGPacket p : packet.getPackets()) {
processSwgPacket(p.getData().array());
++packets;
}
return packets;
}
private int processFrag(Fragmented packet) {
if (packet.getSequence() != (short) (recvSequence+1)) {
if (packet.getSequence() > recvSequence)
eventCallback.sendOutOfOrder(packet.getSequence());
return 0;
}
recvSequence = packet.getSequence();
eventCallback.sendAcknowledge(recvSequence);
return processPacket(fragStream.onReceived(packet));
}
private int processSwgPacket(byte [] data) {
if (data.length < 6)
return 0;
ByteBuffer bb = ByteBuffer.wrap(data);
int crc = bb.order(ByteOrder.LITTLE_ENDIAN).getInt(2);
SWGPacket packet;
if (crc == ObjectController.CRC)
packet = ObjectController.decodeController(bb);
else {
packet = PacketType.getForCrc(crc);
if (packet != null)
packet.decode(bb);
}
if (packet == null)
return 0;
pushPacket(packet);
return 1;
}
public interface InboundEventCallback {
public void sendAcknowledge(short sequence);
public void sendOutOfOrder(short sequence);
}
}
+161 -66
View File
@@ -27,105 +27,200 @@
***********************************************************************************/
package network;
import intents.network.ConnectionOpenedIntent;
import intents.network.InboundPacketIntent;
import java.net.InetAddress;
import java.io.EOFException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.LinkedList;
import java.util.List;
import resources.control.Intent;
import resources.network.ServerType;
import network.encryption.Compression;
import network.packets.Packet;
import network.packets.swg.SWGPacket;
import network.packets.swg.zone.object_controller.ObjectController;
public class NetworkClient {
private static final int DEFAULT_BUFFER = 128;
private final Object prevPacketIntentMutex = new Object();
private final Object outboundMutex = new Object();
private final Object bufferMutex = new Object();
private final InetSocketAddress address;
private final long networkId;
private final ServerType serverType;
private final NetworkProtocol protocol;
private InetAddress address;
private final PacketSender packetSender;
private Intent prevPacketIntent;
private int port;
private int connId;
private ByteBuffer buffer;
private long lastBufferSizeModification;
public NetworkClient(ServerType type, InetAddress addr, int port, long networkId, PacketSender packetSender) {
this.serverType = type;
public NetworkClient(InetSocketAddress address, long networkId, PacketSender packetSender) {
this.address = address;
this.networkId = networkId;
protocol = new NetworkProtocol(type, addr, port, packetSender);
this.packetSender = packetSender;
this.buffer = ByteBuffer.allocate(DEFAULT_BUFFER);
lastBufferSizeModification = System.nanoTime();
prevPacketIntent = null;
connId = 0;
updateNetworkInfo(addr, port);
}
public void updateNetworkInfo(InetAddress addr, int port) {
protocol.updateNetworkInfo(addr, port);
this.address = addr;
this.port = port;
}
public void resetNetwork() {
protocol.resetNetwork();
connId = 0;
}
public void resendOldUnacknowledged() {
protocol.resendOldUnacknowledged();
}
public void setCrc(int crc) {
protocol.setCrc(crc);
}
public void setConnectionId(int id) {
connId = id;
}
public InetAddress getAddress() {
public InetSocketAddress getAddress() {
return address;
}
public int getPort() {
return port;
}
public int getCrc() {
return protocol.getCrc();
}
public int getConnectionId() {
return connId;
}
public long getNetworkId() {
return networkId;
}
public void sendPacket(Packet p) {
protocol.sendPacket(p);
public void onConnected() {
synchronized (prevPacketIntentMutex) {
prevPacketIntent = new ConnectionOpenedIntent(networkId);
prevPacketIntent.broadcast();
}
}
public boolean processPacket(ServerType type, byte [] data) {
if (type != serverType || type == ServerType.UNKNOWN)
return false;
if (type == ServerType.PING)
return true;
List <Packet> packets = protocol.process(data);
for (Packet p : packets) {
p.setAddress(address);
p.setPort(port);
synchronized (prevPacketIntentMutex) {
InboundPacketIntent i = new InboundPacketIntent(type, p, networkId);
if (prevPacketIntent == null)
i.broadcast();
else
i.broadcastAfterIntent(prevPacketIntent);
public void sendPacket(Packet p) {
byte [] encoded = p.encode().array();
int decompressedLength = encoded.length;
boolean compressed = encoded.length >= 16;
if (compressed) {
byte [] compressedData = Compression.compress(encoded);
if (compressedData.length >= encoded.length)
compressed = false;
else
encoded = compressedData;
}
ByteBuffer data = ByteBuffer.allocate(encoded.length + 5).order(ByteOrder.LITTLE_ENDIAN);
byte bitmask = 0;
bitmask |= (compressed?1:0) << 0; // Compressed
bitmask |= 1 << 1; // SWG
data.put(bitmask);
data.putShort((short) encoded.length);
data.putShort((short) decompressedLength);
data.put(encoded);
synchronized (outboundMutex) {
packetSender.sendPacket(address, data.array());
}
}
public void addToBuffer(byte [] data) {
synchronized (bufferMutex) {
if (data.length > buffer.remaining()) { // Increase size
int nCapacity = buffer.capacity() * 2;
while (nCapacity < buffer.position()+data.length)
nCapacity *= 2;
ByteBuffer bb = ByteBuffer.allocate(nCapacity);
buffer.flip();
bb.put(buffer);
bb.put(data);
this.buffer = bb;
lastBufferSizeModification = System.nanoTime();
} else {
buffer.put(data);
if (buffer.position() < buffer.capacity()/4 && (System.nanoTime()-lastBufferSizeModification) >= 1E9)
shrinkBuffer();
}
}
}
public boolean process() {
List <Packet> packets;
synchronized (bufferMutex) {
buffer.flip();
packets = processPackets();
buffer.compact();
}
synchronized (prevPacketIntentMutex) {
for (Packet p : packets) {
p.setAddress(address.getAddress());
p.setPort(address.getPort());
InboundPacketIntent i = new InboundPacketIntent(p, networkId);
i.broadcastAfterIntent(prevPacketIntent);
prevPacketIntent = i;
}
}
return packets.size() > 0;
}
private void shrinkBuffer() {
synchronized (bufferMutex) {
int nCapacity = DEFAULT_BUFFER;
while (nCapacity < buffer.position())
nCapacity *= 2;
if (nCapacity >= buffer.capacity())
return;
ByteBuffer bb = ByteBuffer.allocate(nCapacity).order(ByteOrder.LITTLE_ENDIAN);
buffer.flip();
bb.put(buffer);
buffer = bb;
lastBufferSizeModification = System.nanoTime();
}
}
private List<Packet> processPackets() {
List <Packet> packets = new LinkedList<>();
Packet p = null;
try {
while (buffer.hasRemaining()) {
p = processPacket();
if (p != null)
packets.add(p);
}
} catch (EOFException e) {
System.err.println(e.getMessage());
}
return packets;
}
private Packet processPacket() throws EOFException {
if (buffer.remaining() < 5)
throw new EOFException("Not enough remaining data for header! Remaining: " + buffer.remaining());
buffer.order(ByteOrder.LITTLE_ENDIAN);
byte bitfield = buffer.get();
boolean compressed = (bitfield & (1<<0)) != 0;
boolean swg = (bitfield & (1<<1)) != 0;
int length = buffer.getShort();
int decompressedLength = buffer.getShort();
if (buffer.remaining() < length) {
buffer.position(buffer.position() - 5);
throw new EOFException("Not enough remaining data! Remaining: " + buffer.remaining() + " Length: " + length);
}
byte [] pData = new byte[length];
buffer.get(pData);
if (compressed) {
pData = Compression.decompress(pData, decompressedLength);
}
if (swg)
return processSWG(pData);
else
return processProtocol(pData);
}
private Packet processProtocol(byte [] data) {
return null;
}
private SWGPacket processSWG(byte [] data) {
if (data.length < 6) {
System.err.println("Length too small: " + data.length);
return null;
}
ByteBuffer buffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
int crc = buffer.getInt(2);
if (crc == 0x80CE5E46)
return ObjectController.decodeController(buffer);
else {
SWGPacket packet = PacketType.getForCrc(crc);
if (packet != null)
packet.decode(buffer);
return packet;
}
}
public String toString() {
return "NetworkClient[ConnId=" + connId + " " + address + ":" + port + "]";
return "NetworkClient["+address+"]";
}
}
-154
View File
@@ -1,154 +0,0 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 network;
import java.net.InetAddress;
import java.util.LinkedList;
import java.util.List;
import resources.network.ServerType;
import resources.network.UDPServer.UDPPacket;
import resources.server_info.Log;
import network.InboundNetworkHandler.InboundEventCallback;
import network.packets.Packet;
import network.packets.soe.Acknowledge;
import network.packets.soe.ClientNetworkStatusUpdate;
import network.packets.soe.OutOfOrder;
import network.packets.soe.ServerNetworkStatusUpdate;
public class NetworkProtocol implements InboundEventCallback {
private final InboundNetworkHandler inbound;
private final OutboundNetworkHandler outbound;
private final ServerType serverType;
private final PacketSender packetSender;
private InetAddress address;
private int port;
private int crc;
public NetworkProtocol(ServerType type, InetAddress address, int port, PacketSender packetSender) {
this.inbound = new InboundNetworkHandler(this);
this.outbound = new OutboundNetworkHandler();
this.serverType = type;
this.packetSender = packetSender;
crc = 0;
updateNetworkInfo(address, port);
}
public void setCrc(int crc) {
this.crc = crc;
inbound.setCrc(crc);
outbound.setCrc(crc);
}
public int getCrc() {
return crc;
}
@Override
public void sendAcknowledge(short sequence) {
sendPacket(new Acknowledge(sequence));
}
@Override
public void sendOutOfOrder(short sequence) {
sendPacket(new OutOfOrder(sequence));
}
public void updateNetworkInfo(InetAddress addr, int port) {
this.address = addr;
this.port = port;
}
public void resetNetwork() {
inbound.reset();
outbound.reset();
}
public void resendOldUnacknowledged() {
outbound.resendOldUnacknowledged();
flushAssembled();
}
public List <Packet> process(byte [] data) {
inbound.onReceive(data);
List <Packet> packets = new LinkedList<Packet>();
while (inbound.hasInbound()) {
process(packets, inbound.pollInbound());
}
return packets;
}
private void process(List <Packet> packets, Packet packet) {
if (packet == null)
throw new NullPointerException("Inbound packet cannot be null!");
packets.add(packet);
if (packet instanceof OutOfOrder)
outbound.onOutOfOrder(((OutOfOrder) packet).getSequence());
else if (packet instanceof Acknowledge)
outbound.onAcknowledge(((Acknowledge) packet).getSequence());
else if (packet instanceof ClientNetworkStatusUpdate)
processClientNetworkUpdate((ClientNetworkStatusUpdate) packet);
flushAssembled();
}
public void sendPacket(Packet packet) {
if (address == null) {
Log.w("NetworkProtocol", "Address is null! Cannot send packet");
return;
}
outbound.assemble(packet);
flushAssembled();
}
private void send(byte [] data) {
if (data == null)
throw new NullPointerException("Outbound data cannot be null!");
packetSender.sendPacket(serverType, new UDPPacket(address, port, data));
}
private void processClientNetworkUpdate(ClientNetworkStatusUpdate update) {
ServerNetworkStatusUpdate serverNet = new ServerNetworkStatusUpdate();
serverNet.setClientTickCount((short) update.getTick());
serverNet.setServerSyncStampLong(0);
int recv = inbound.getReceivedSequence() < 0 ? 0 : inbound.getReceivedSequence();
int send = outbound.getSentSequence();
serverNet.setClientPacketsSent(recv);
serverNet.setClientPacketsRecv(send);
serverNet.setServerPacketsSent(send);
serverNet.setServerPacketsRecv(recv);
sendPacket(serverNet);
}
private void flushAssembled() {
while (outbound.hasAssembled())
send(outbound.pollAssembled());
}
}
-311
View File
@@ -1,311 +0,0 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 network;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import resources.SortedLinkedList;
import network.encryption.Encryption;
import network.packets.Packet;
import network.packets.soe.DataChannelA;
import network.packets.soe.Fragmented;
import network.packets.soe.MultiPacket;
import network.packets.soe.SessionRequest;
import network.packets.soe.SessionResponse;
import network.packets.swg.SWGPacket;
public class OutboundNetworkHandler {
private static final long RESEND_TIMEOUT = TimeUnit.MILLISECONDS.toMillis(3000);
private final Queue <byte []> assembleQueue;
private final SortedLinkedList <SequencedPacket> sequenced;
private short sendSequence;
private int crc;
public OutboundNetworkHandler() {
assembleQueue = new LinkedList<byte []>();
sequenced = new SortedLinkedList<SequencedPacket>();
sendSequence = 0;
crc = 0;
}
public synchronized void reset() {
sequenced.clear();
assembleQueue.clear();
sendSequence = 0;
crc = 0;
}
public synchronized void setCrc(int crc) {
this.crc = crc;
}
public synchronized int getCrc() {
return crc;
}
public synchronized short getSentSequence() {
return sendSequence;
}
public synchronized void onAcknowledge(short sequence) {
synchronized (sequenced) {
Iterator <SequencedPacket> it = sequenced.listIterator();
while (it.hasNext()) {
SequencedPacket sp = it.next();
if (sp.getSequence() <= sequence) {
it.remove();
} else {
if (sp.isSent())
sp.setSent(false);
else
break;
}
}
}
}
public synchronized void onOutOfOrder(short sequence) {
synchronized (sequenced) {
Iterator <SequencedPacket> it = sequenced.listIterator();
while (it.hasNext()) {
SequencedPacket sp = it.next();
if (sp.getSequence() > sequence) {
if (sp.isSent())
sp.setSent(false);
else
break;
} else if (!sp.isSent() || sp.getSequence() == sequence) {
pushAssembledUnencrypted(sp.getPacket()); // Pre-encrypted before putting into list
sp.setSent(true);
sp.updateSent();
}
}
}
}
public synchronized boolean hasAssembled() {
synchronized (assembleQueue) {
return !assembleQueue.isEmpty();
}
}
public synchronized byte [] pollAssembled() {
synchronized (assembleQueue) {
return assembleQueue.poll();
}
}
public synchronized void resendOldUnacknowledged() {
synchronized (sequenced) {
for (SequencedPacket packet : sequenced) {
if (packet.hasBeen(RESEND_TIMEOUT)) {
pushAssembledUnencrypted(packet.getPacket()); // Pre-encrypted before putting into list
packet.setSent(true);
packet.updateSent();
}
}
}
}
private byte [] pushAssembledEncrypted(byte [] data) {
data = Encryption.encode(data, crc);
synchronized (assembleQueue) {
assembleQueue.add(data);
}
return data;
}
private void pushAssembledUnencrypted(byte [] data) {
synchronized (assembleQueue) {
assembleQueue.add(data);
}
}
private void pushSequencedPacket(short sequence, byte [] packet) {
synchronized (sequenced) {
sequenced.add(new SequencedPacket(sequence, packet));
}
}
public synchronized int assemble(Packet packet) {
if (packet instanceof SessionRequest || packet instanceof SessionResponse) {
pushAssembledUnencrypted(packet.encode().array());
return 1;
} else
return assembleUnencrypted(packet);
}
private int assembleUnencrypted(Packet packet) {
if (packet instanceof SWGPacket)
return assembleSwg((SWGPacket) packet);
else
return assembleSoe(packet);
}
private int assembleSoe(Packet packet) {
if (packet instanceof DataChannelA)
return assembleDataChannelA((DataChannelA) packet);
if (packet instanceof MultiPacket)
return assembleMultiPacket((MultiPacket) packet);
pushAssembledEncrypted(packet.encode().array());
return 1;
}
private int assembleSwg(SWGPacket packet) {
return assembleDataChannelA(new DataChannelA(packet));
}
private int assembleMultiPacket(MultiPacket m) {
int len = m.getLength();
if (len >= 493) {
int count = getFragmentedPacketCount(len);
int lastSeq = updateSequencesMulti((short)(sendSequence+count), m);
for (Fragmented f : Fragmented.encode(m.encode(), sendSequence)) {
byte [] encoded = f.encode().array();
byte [] encrypted = pushAssembledEncrypted(encoded);
pushSequencedPacket(f.getSequence(), encrypted);
}
sendSequence = (short) (lastSeq + 1);
return count;
} else {
sendSequence = updateSequencesMulti(sendSequence, m);
pushAssembledEncrypted(m.encode().array());
return 1;
}
}
private int assembleDataChannelA(DataChannelA d) {
int len = d.getLength();
if (len >= 493) {
int count = getFragmentedPacketCount(len);
int lastSeq = updateSequenceData((short)(sendSequence+count), d);
for (Fragmented f : Fragmented.encode(d.encode(), sendSequence)) {
byte [] encoded = f.encode().array();
byte [] encrypted = pushAssembledEncrypted(encoded);
pushSequencedPacket(f.getSequence(), encrypted);
}
sendSequence = (short) lastSeq;
return count;
} else {
d.setSequence(sendSequence++);
byte [] encoded = d.encode().array();
byte [] encrypted = pushAssembledEncrypted(encoded);
pushSequencedPacket(d.getSequence(), encrypted);
return 1;
}
}
private short updateSequencesMulti(short seq, MultiPacket m) {
for (Packet p : m.getPackets()) {
if (p instanceof DataChannelA)
seq = updateSequenceData(seq, (DataChannelA) p);
}
return seq;
}
private short updateSequenceData(short seq, DataChannelA d) {
d.setSequence(seq++);
return seq;
}
private int getFragmentedPacketCount(int length) {
return (int) Math.ceil((length+4)/489.0);
}
private static class SequencedPacket implements Comparable <SequencedPacket> {
private final short sequence;
private final byte [] packet;
private long sentTime;
private boolean sent;
public SequencedPacket(short sequence, byte [] packet) {
this.sequence = sequence;
this.packet = packet;
this.sentTime = System.nanoTime();
sent = false;
}
public short getSequence() {
return sequence;
}
public byte [] getPacket() {
return packet;
}
public boolean isSent() {
return sent;
}
public void setSent(boolean sent) {
this.sent = sent;
}
public boolean hasBeen(double milliseconds) {
return hasBeen() >= milliseconds;
}
public double hasBeen() {
return (System.nanoTime() - sentTime) / 1E6;
}
public void updateSent() {
sentTime = System.nanoTime();
}
@Override
public int compareTo(SequencedPacket sp) {
if (sequence < sp.getSequence())
return -1;
if (sequence == sp.getSequence())
return 0;
return 1;
}
@Override
public boolean equals(Object o) {
if (o == null)
return false;
if (o instanceof SequencedPacket)
return ((SequencedPacket) o).getSequence() == sequence;
return false;
}
@Override
public int hashCode() {
return sequence;
}
}
}
+10 -175
View File
@@ -1,190 +1,25 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 network;
import intents.network.CloseConnectionIntent;
import intents.network.OutboundPacketIntent;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import resources.control.Intent;
import resources.control.Service;
import network.packets.Packet;
import network.packets.soe.DataChannelA;
import network.packets.soe.MultiPacket;
import network.packets.soe.SessionResponse;
import network.packets.swg.SWGPacket;
public class OutboundPacketService {
private final Map <Long, OutboundPacketSender> outboundPackets = new HashMap<Long, OutboundPacketSender>();
private final Object outboundMutex = new Object();
private Intent previousOutboundIntent = null;
public OutboundPacketService() {
new Service() {
public void onIntentReceived(Intent i) {
if (i instanceof CloseConnectionIntent)
closeConnection(((CloseConnectionIntent)i).getNetworkId());
}
}.registerForIntent(CloseConnectionIntent.TYPE);
public void send(long networkId, Packet ... packets) {
for (Packet packet : packets)
send(networkId, packet);
}
public void sendPacket(long networkId, Packet ... packets) {
getSender(networkId).add(packets);
}
public void sendPacket(long networkId, Packet packet) {
getSender(networkId).add(packet);
}
public int flushPackets() {
int count = 0;
synchronized (outboundPackets) {
for (OutboundPacketSender sender : outboundPackets.values())
count += sender.sendPackets();
public void send(long networkId, Packet packet) {
synchronized (outboundMutex) {
Intent i = new OutboundPacketIntent(packet, networkId);
i.broadcastAfterIntent(previousOutboundIntent);
previousOutboundIntent = i;
}
return count;
}
private void closeConnection(long networkId) {
synchronized (outboundPackets) {
outboundPackets.remove(networkId);
}
}
private OutboundPacketSender getSender(long networkId) {
synchronized (outboundPackets) {
OutboundPacketSender outbound = outboundPackets.get(networkId);
if (outbound == null) {
outbound = new OutboundPacketSender(networkId);
outboundPackets.put(networkId, outbound);
}
return outbound;
}
}
private static class OutboundPacketSender {
private final List <Packet> outbound;
private final long networkId;
private Intent prevOutbound;
private boolean hasSoe;
private boolean hasSwg;
public OutboundPacketSender(long networkId) {
outbound = new LinkedList<Packet>();
this.networkId = networkId;
prevOutbound = null;
hasSoe = false;
hasSwg = false;
}
public synchronized void add(Packet ... packets) {
for (Packet p : packets)
add(p);
}
public synchronized void add(Packet p) {
if (p instanceof SessionResponse) {
send(p);
} else {
if (p instanceof SWGPacket)
hasSwg = true;
else
hasSoe = true;
outbound.add(p);
}
}
public synchronized int sendPackets() {
if (outbound.isEmpty())
return 0;
int size = outbound.size();
packageAndSendPackets();
return size;
}
private synchronized void send(Packet p) {
Intent out = new OutboundPacketIntent(p, networkId);
out.broadcastAfterIntent(prevOutbound);
prevOutbound = out;
}
private synchronized void clear() {
hasSoe = false;
hasSwg = false;
outbound.clear();
}
private synchronized void packageAndSendPackets() {
if (hasSwg) {
if (hasSoe)
packageMix();
else
packageSwg();
} else {
if (hasSoe)
packageSoe();
}
clear();
}
private synchronized void packageSoe() {
send(new MultiPacket(new LinkedList<Packet>(outbound)));
}
private synchronized void packageSwg() {
send(new DataChannelA(outbound.toArray(new SWGPacket[outbound.size()])));
}
private synchronized void packageMix() {
MultiPacket multi = new MultiPacket();
DataChannelA data = null;
for (Packet p : outbound) {
if (p instanceof SWGPacket) {
if (data == null)
data = new DataChannelA();
data.addPacket((SWGPacket) p);
} else {
if (data != null) {
multi.addPacket(data);
data = null;
}
multi.addPacket(p);
}
}
if (data != null)
multi.addPacket(data);
send(multi);
}
}
}
+2 -3
View File
@@ -1,10 +1,9 @@
package network;
import resources.network.ServerType;
import resources.network.UDPServer.UDPPacket;
import java.net.InetSocketAddress;
public interface PacketSender {
void sendPacket(ServerType type, UDPPacket packet);
void sendPacket(InetSocketAddress sock, byte [] data);
}
+6 -2
View File
@@ -45,6 +45,8 @@ import network.packets.swg.zone.spatial.*;
import java.util.HashMap;
import java.util.Map;
import resources.server_info.Log;
public enum PacketType {
// Both
@@ -222,13 +224,15 @@ public enum PacketType {
public static SWGPacket getForCrc(int crc) {
PacketType type = packetMap.get(crc);
if (type == null)
if (type == null) {
Log.w("PacketType", "Unknown packet: %08X", crc);
return null;
}
Class <? extends SWGPacket> c = type.c;
try {
return c.newInstance();
} catch (Exception e) {
System.err.println("Packet: " + c.getName());
System.err.printf("Packet: [%08X] %s%n", crc, c.getName());
e.printStackTrace();
}
return null;
+35
View File
@@ -0,0 +1,35 @@
package network.encryption;
import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4SafeDecompressor;
public class Compression {
private static final LZ4Compressor COMPRESSOR = LZ4Factory.safeInstance().highCompressor();
private static final LZ4SafeDecompressor DECOMPRESSOR = LZ4Factory.safeInstance().safeDecompressor();
public static byte [] compress(byte [] data) {
int maxCompressedLength = COMPRESSOR.maxCompressedLength(data.length);
byte[] compressed = new byte[maxCompressedLength];
int length = COMPRESSOR.compress(data, compressed);
byte [] ret = new byte[length];
System.arraycopy(compressed, 0, ret, 0, length);
return ret;
}
public static byte [] decompress(byte [] data) {
return decompress(data, data.length * 10);
}
public static byte [] decompress(byte [] data, int bufferSize) {
byte [] restored = new byte[bufferSize];
int length = DECOMPRESSOR.decompress(data, restored);
if (length == bufferSize)
return restored;
byte [] ret = new byte[length];
System.arraycopy(restored, 0, ret, 0, length);
return ret;
}
}
@@ -1,107 +0,0 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 network.packets.soe;
import java.nio.ByteBuffer;
import network.packets.Packet;
public class ClientNetworkStatusUpdate extends Packet {
private int clientTickCount;
private int lastUpdate;
private int avgUpdate;
private int shortUpdate;
private int longUpdate;
private int lastServerUpdate;
private long packetSent;
private long packetRecv;
public ClientNetworkStatusUpdate() {
}
public ClientNetworkStatusUpdate(ByteBuffer data) {
decode(data);
}
public ClientNetworkStatusUpdate(int clientTickCount, int lastUpdate, int avgUpdate, int shortUpdate, int longUpdate, int lastServerUpdate, long packetsSent, long packetsRecv) {
this.clientTickCount = clientTickCount;
this.lastUpdate = lastUpdate;
this.avgUpdate = avgUpdate;
this.shortUpdate = shortUpdate;
this.longUpdate = longUpdate;
this.lastServerUpdate = lastServerUpdate;
this.packetSent = packetsSent;
this.packetRecv = packetsRecv;
}
public void decode(ByteBuffer data) {
data.position(2);
clientTickCount = getNetShort(data);
lastUpdate = getNetInt(data);
avgUpdate = getNetInt(data);
shortUpdate = getNetInt(data);
longUpdate = getNetInt(data);
lastServerUpdate = getNetInt(data);
packetSent = getNetLong(data);
packetRecv = getNetLong(data);
}
public ByteBuffer encode() {
ByteBuffer data = ByteBuffer.allocate(40);
addNetShort(data, 7);
addNetShort(data, clientTickCount);
addNetInt( data, lastUpdate);
addNetInt( data, avgUpdate);
addNetInt( data, shortUpdate);
addNetInt( data, longUpdate);
addNetInt( data, lastServerUpdate);
addNetLong( data, packetSent);
addNetLong( data, packetRecv);
return data;
}
public int getTick() { return clientTickCount; }
public int getLastUpdate() { return lastUpdate; }
public int getAverageUpdate() { return avgUpdate; }
public int getShortestUpdate() { return shortUpdate; }
public int getLongestUpdate() { return longUpdate; }
public int getLastServerUpdate() { return lastServerUpdate; }
public long getSent() { return packetSent; }
public long getRecv() { return packetRecv; }
public void setTick(int tick) { this.clientTickCount = tick; }
public void setLastUpdate(int last) { this.lastUpdate = last; }
public void setAverageUpdate(int avg) { this.avgUpdate = avg; }
public void setShortestUpdate(int shortest) { this.shortUpdate = shortest; }
public void setLongestUpdate(int longest) { this.longUpdate = longest; }
public void setLastServerUpdate(int last) { this.lastServerUpdate = last; }
public void setPacketsSent(long sent) { this.packetSent = sent; }
public void setPacketsRecv(long recv) { this.packetRecv = recv; }
}
-180
View File
@@ -1,180 +0,0 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 network.packets.soe;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import network.packets.Packet;
import network.packets.swg.SWGPacket;
public class DataChannelA extends Packet implements Comparable<DataChannelA> {
private List <SWGPacket> content = new ArrayList<SWGPacket>();
private short sequence = 0;
private short multiPacket = 0;
public DataChannelA() {
}
public DataChannelA(ByteBuffer data) {
decode(data);
}
public DataChannelA(SWGPacket packet) {
content.add(packet);
}
public DataChannelA(List <SWGPacket> packets) {
content = packets;
}
public DataChannelA(SWGPacket [] packets) {
for (SWGPacket p : packets) {
content.add(p);
}
}
public void decode(ByteBuffer data) {
super.decode(data);
if (getOpcode() != 9)
return;
data.position(2);
sequence = getNetShort(data);
multiPacket = getNetShort(data);
if (multiPacket == 0x19) {
int length = 0;
while (data.remaining() > 1) {
length = getByte(data) & 0xFF;
if (length == 0xFF)
length = getNetShort(data);
if (length > data.remaining()) {
data.position(data.position()-1);
return;
}
ByteBuffer pData = ByteBuffer.allocate(length);
data.get(pData.array());
SWGPacket packet = new SWGPacket();
packet.decode(pData);
content.add(packet);
}
} else {
data.position(data.position()-2);
ByteBuffer pData = ByteBuffer.allocate(data.remaining());
data.get(pData.array());
SWGPacket packet = new SWGPacket();
packet.decode(pData);
content.add(packet);
}
}
public ByteBuffer encode() {
return encode(this.sequence);
}
public ByteBuffer encode(int sequence) {
this.sequence = (short) sequence;
if (content.size() == 1) {
byte [] pData = content.get(0).encode().array();
ByteBuffer data = ByteBuffer.allocate(4 + pData.length);
addNetShort(data, 9);
addNetShort(data, sequence);
data.put(pData);
return data;
} else if (content.size() > 1) {
int length = getLength();
ByteBuffer data= ByteBuffer.allocate(length);
addNetShort(data, 9);
addNetShort(data, sequence);
addNetShort(data, 0x19);
for (SWGPacket packet : content) {
byte [] pData = packet.encode().array();
if (pData.length >= 0xFF) {
addByte(data, 0xFF);
addNetShort(data, pData.length);
} else {
data.put((byte) pData.length);
}
data.put(pData);
}
return data;
} else {
return ByteBuffer.allocate(0);
}
}
public void addPacket(SWGPacket packet) {
content.add(packet);
}
public void clearPackets() {
content.clear();
}
public int getLength() {
if (content.size() == 1) {
return 4 + content.get(0).encode().array().length;
} else {
int length = 6;
for (SWGPacket packet : content) {
int addLength = packet.encode().array().length;
length += 1 + addLength + ((addLength >= 0xFF) ? 2 : 0);
}
return length;
}
}
@Override
public int compareTo(DataChannelA d) {
if (sequence < d.sequence)
return -1;
if (sequence == d.sequence)
return 0;
return 1;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof DataChannelA))
return false;
return ((DataChannelA) o).sequence == sequence;
}
@Override
public int hashCode() {
return sequence;
}
public void setSequence(short sequence) { this.sequence = sequence; }
public short getSequence() { return sequence; }
public List <SWGPacket> getPackets() { return content; }
}
-105
View File
@@ -1,105 +0,0 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 network.packets.soe;
import java.nio.ByteBuffer;
import network.packets.Packet;
public class Disconnect extends Packet {
private int connectionId;
private DisconnectReason reason;
public Disconnect() {
connectionId = 0;
reason = DisconnectReason.NONE;
}
public Disconnect(int connectionId, DisconnectReason reason) {
this.connectionId = connectionId;
this.reason = reason;
}
public Disconnect(ByteBuffer data){
this.decode(data);
}
public void decode(ByteBuffer data) {
data.position(2);
connectionId = getNetInt(data);
reason = getReason(getNetShort(data));
}
public ByteBuffer encode() {
ByteBuffer data = ByteBuffer.allocate(8);
addNetShort(data, 5);
addNetInt(data, connectionId);
addNetShort(data, reason.getReason());
return data;
}
public int getConnectionID() { return connectionId; }
public DisconnectReason getReason() { return reason; }
private DisconnectReason getReason(int reason) {
for (DisconnectReason dr : DisconnectReason.values())
if (dr.getReason() == reason)
return dr;
return DisconnectReason.NONE;
}
public enum DisconnectReason {
NONE (0x00),
ICMP_ERROR (0x01),
TIMEOUT (0x02),
OTHER_SIDE_TERMINATED (0x03),
MANAGER_DELETED (0x04),
CONNECT_FAIL (0x05),
APPLICATION (0x06),
UNREACHABLE_CONNECTION (0x07),
UNACKNOWLEDGED_TIMEOUT (0x08),
NEW_CONNECTION_ATTEMPT (0x09),
CONNECTION_REFUSED (0x0A),
MUTUAL_CONNETION_ERROR (0x0B),
CONNETING_TO_SELF (0x0C),
RELIABLE_OVERFLOW (0x0D),
COUNT (0x0E);
private short reason;
DisconnectReason(int reason) {
this.reason = (short) reason;
}
public short getReason() {
return reason;
}
}
}
-141
View File
@@ -1,141 +0,0 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 network.packets.soe;
import java.nio.ByteBuffer;
import network.packets.Packet;
public class Fragmented extends Packet implements Comparable<Fragmented> {
private short sequence;
private int length;
private ByteBuffer packet;
private ByteBuffer data;
public Fragmented() {
this.sequence = 0;
this.length = 0;
this.packet = null;
this.data = null;
}
public Fragmented(ByteBuffer data) {
decode(data);
length = -1;
}
public Fragmented(ByteBuffer data, int sequence) {
this.sequence = (short) sequence;
decode(data);
length = -1;
}
public void setPacket(ByteBuffer packet) {
this.packet = packet;
}
public void decode(ByteBuffer data) {
data.position(2);
sequence = getNetShort(data);
this.data = data;
}
public ByteBuffer encode() {
return data;
}
public Fragmented [] encode(int startSequence) {
packet.position(0);
int ord = 0;
Fragmented [] packets = new Fragmented[(int) Math.ceil((packet.remaining()+4)/489.0)];
while (packet.remaining() > 0) {
packets[ord] = createSegment(startSequence++, ord++, packet);
}
return packets;
}
@Override
public int compareTo(Fragmented f) {
if (sequence < f.sequence)
return -1;
if (sequence == f.sequence)
return 0;
return 1;
}
@Override
public boolean equals(Object o) {
if (o instanceof Fragmented)
return ((Fragmented) o).sequence == sequence;
if (o instanceof Number)
return ((Number) o).shortValue() == sequence;
return false;
}
@Override
public int hashCode() {
return sequence;
}
public ByteBuffer getPacketData() { return data; }
public short getSequence() { return sequence; }
public int getDatLength() { return length; }
public static final Fragmented [] encode(ByteBuffer data, int startSequence) {
data.position(0);
int ord = 0;
Fragmented [] packets = new Fragmented[(int) Math.ceil((data.remaining()+4)/489.0)];
while (data.remaining() > 0) {
packets[ord] = createSegment(startSequence++, ord++, data);
}
return packets;
}
private static final Fragmented createSegment(int startSequence, int ord, ByteBuffer packet) {
int header = (ord == 0) ? 8 : 4;
ByteBuffer data = ByteBuffer.allocate(Math.min(packet.remaining()+header, 493));
addNetShort(data, 0x0D);
addNetShort(data, startSequence);
if (ord == 0)
addNetInt(data, packet.remaining());
int len = data.remaining();
data.put(packet.array(), packet.position(), len);
packet.position(packet.position() + len);
byte [] pData = new byte[data.array().length-header];
System.arraycopy(data.array(), header, pData, 0, pData.length);
Fragmented f = new Fragmented(data, startSequence);
f.packet = ByteBuffer.wrap(pData);
return f;
}
}
-140
View File
@@ -1,140 +0,0 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 network.packets.soe;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import network.packets.Packet;
public class MultiPacket extends Packet {
private List <Packet> content = new ArrayList<Packet>();
public MultiPacket() {
this(new ArrayList<Packet>());
}
public MultiPacket(ByteBuffer data) {
this(new ArrayList<Packet>());
decode(data);
}
public MultiPacket(List <Packet> packets) {
this.content = packets;
}
public void decode(ByteBuffer data) {
data.position(2);
int length = data.array().length;
int pLength = 0;
for (int i = 2; i < length; i += pLength) {
if (data.remaining() < 1)
return;
pLength = getByte(data) & 0xFF;
if (pLength == 255) {
if (data.remaining() < 2)
return;
pLength = data.order(ByteOrder.LITTLE_ENDIAN).getShort();
}
if (pLength > data.remaining()) {
data.position(data.position()-1);
return;
}
byte [] pData = new byte[pLength];
data.get(pData);
Packet p = new Packet();
p.decode(ByteBuffer.wrap(pData));
content.add(p);
}
}
public ByteBuffer encode() {
int length = 2;
for (Packet packet : content) {
int pLength = packet.encode().array().length;
if (pLength >= 255) {
length += 3;
} else {
length += 1;
}
length += pLength;
}
ByteBuffer data = ByteBuffer.allocate(length);
data.order(ByteOrder.BIG_ENDIAN).putShort((short)3);
for (Packet packet : content) {
byte [] pData = packet.encode().array();
if (pData.length >= 255) {
data.put((byte)255);
addShort(data, (short)pData.length);
} else {
data.put((byte)pData.length);
}
data.put(pData);
}
return data;
}
public int getLength() {
int length = 2;
for (Packet packet : content) {
int pLength = getPacketLength(packet);
if (pLength >= 255) {
length += 3;
} else {
length += 1;
}
length += pLength;
}
return length;
}
private int getPacketLength(Packet packet) {
if (packet instanceof DataChannelA)
return ((DataChannelA) packet).getLength();
else if (packet instanceof Acknowledge || packet instanceof OutOfOrder)
return 4;
else if (packet instanceof Disconnect)
return 8;
return packet.encode().array().length;
}
public void addPacket(Packet packet) {
content.add(packet);
}
public void clearPackets() {
content.clear();
}
public List <Packet> getPackets() {
return content;
}
}
@@ -1,96 +0,0 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 network.packets.soe;
import java.nio.ByteBuffer;
import network.packets.Packet;
public class ServerNetworkStatusUpdate extends Packet {
private short clientTickCount = 0;
private int serverSyncStampLong = 0;
private long clientPacketsSent = 0;
private long clientPacketsRecv = 0;
private long serverPacketsSent = 0;
private long serverPacketsRecv = 0;
public ServerNetworkStatusUpdate() {
}
public ServerNetworkStatusUpdate(ByteBuffer data) {
decode(data);
}
public ServerNetworkStatusUpdate(int clientTickCount, long clientSent, long clientRecv, long serverSent, long serverRecv) {
this.clientTickCount = (short) clientTickCount;
this.serverSyncStampLong = 0;
this.clientPacketsSent = clientSent;
this.clientPacketsRecv = clientRecv;
this.serverPacketsSent = serverSent;
this.serverPacketsRecv = serverRecv;
}
public void decode(ByteBuffer data) {
data.position(2);
clientTickCount = getNetShort(data);
serverSyncStampLong = getNetInt(data);
clientPacketsSent = getNetLong(data);
clientPacketsRecv = getNetLong(data);
serverPacketsSent = getNetLong(data);
serverPacketsRecv = getNetLong(data);
}
public ByteBuffer encode() {
ByteBuffer data = ByteBuffer.allocate(40);
addNetShort(data, 8);
addNetShort(data, clientTickCount);
addNetInt( data, serverSyncStampLong);
addNetLong( data, clientPacketsSent);
addNetLong( data, clientPacketsRecv);
addNetLong( data, serverPacketsSent);
addNetLong( data, serverPacketsRecv);
return data;
}
public short getClientTickCount() { return clientTickCount; }
public int getServerSyncStampLong() { return serverSyncStampLong; }
public long getClientPacketsSent() { return clientPacketsSent; }
public long getClientPacketsRecv() { return clientPacketsRecv; }
public long getServerPacketsSent() { return serverPacketsSent; }
public long getServerPacketsRecv() { return serverPacketsRecv; }
public void setClientTickCount(short tick) { this.clientTickCount = tick; }
public void setServerSyncStampLong(int sync) { this.serverSyncStampLong = sync; }
public void setClientPacketsSent(int sent) { this.clientPacketsSent = sent; }
public void setClientPacketsRecv(int recv) { this.clientPacketsRecv = recv; }
public void setServerPacketsSent(int sent) { this.serverPacketsSent = sent; }
public void setServerPacketsRecv(int recv) { this.serverPacketsRecv = recv; }
}
@@ -1,76 +0,0 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 network.packets.soe;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import network.packets.Packet;
public class SessionRequest extends Packet {
private int crcLength;
private int connectionID;
private int udpSize;
public SessionRequest() {
}
public SessionRequest(ByteBuffer data) {
decode(data);
}
public SessionRequest(int crcLength, int connectionID, int udpSize) {
this.crcLength = crcLength;
this.connectionID = connectionID;
this.udpSize = udpSize;
}
public void decode(ByteBuffer packet) {
super.decode(packet);
packet.position(2);
crcLength = getNetInt(packet);
connectionID = getNetInt(packet);
udpSize = getNetInt(packet);
}
public ByteBuffer encode() {
ByteBuffer bb = ByteBuffer.allocate(14).order(ByteOrder.BIG_ENDIAN);
addNetShort(bb, 1);
addNetInt(bb, crcLength);
addNetInt(bb, connectionID);
addNetInt(bb, udpSize);
return bb;
}
public int getCrcLength() { return crcLength; }
public int getConnectionID() { return connectionID; }
public int getUdpSize() { return udpSize; }
}
@@ -1,103 +0,0 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 network.packets.soe;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import network.packets.Packet;
public class SessionResponse extends Packet {
private int connectionID;
private int crcSeed;
private byte crcLength;
private byte encryptionFlag;
private byte xorLength;
private int udpSize;
public SessionResponse() {
}
public SessionResponse(ByteBuffer data) {
decode(data);
}
public SessionResponse(int connectionID,
int crcSeed,
byte crcLength,
byte encryptionFlag,
byte xorLength,
int udpSize) {
this.connectionID = connectionID;
this.crcSeed = crcSeed;
this.crcLength = crcLength;
this.encryptionFlag = encryptionFlag;
this.xorLength = xorLength;
this.udpSize = udpSize;
}
public void decode(ByteBuffer data) {
super.decode(data);
data.position(2);
connectionID = getNetInt(data);
crcSeed = getNetInt(data);
crcLength = data.get();
encryptionFlag = data.get();
xorLength = data.get();
udpSize = getNetInt(data);
}
public ByteBuffer encode() {
ByteBuffer bb = ByteBuffer.allocate(17).order(ByteOrder.BIG_ENDIAN);
addNetShort(bb, 2);
addNetInt( bb, connectionID);
addNetInt( bb, crcSeed);
addByte( bb, crcLength);
addByte( bb, encryptionFlag);
addByte( bb, xorLength);
addNetInt( bb, udpSize);
return bb;
}
public int getConnectionID() { return connectionID; }
public int getCrcSeed() { return crcSeed; }
public byte getCrcLength() { return crcLength; }
public short getEncryptionFlag() { return encryptionFlag; }
public byte getXorLength() { return xorLength; }
public int getUdpSize() { return udpSize; }
public void setConnectionID(int id) { this.connectionID = id; }
public void setCrcSeed(int crc) { this.crcSeed = crc; }
public void setCrcLength(int length) { this.crcLength = (byte) length; }
public void setEncryptionFlag(short flag) { this.encryptionFlag = (byte) flag; }
public void setXorLength(byte xorLength) { this.xorLength = xorLength; }
public void setUdpSize(int size) { this.udpSize = size; }
}
@@ -56,7 +56,6 @@ public class LoginClusterStatus extends SWGPacket {
g.setZonePort(getShort(data));
g.setPingPort(getShort(data));
g.setPopulation(getInt(data));
g.setPopulationStatus(getInt(data));
g.setMaxCharacters(getInt(data));
g.setTimeZone(getInt(data));
g.setStatus(getInt(data));
@@ -25,44 +25,40 @@
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package network.packets.soe;
package network.packets.swg.zone.object_controller;
import java.nio.ByteBuffer;
import network.packets.Packet;
public class Acknowledge extends Packet {
public class IntendedTarget extends ObjectController {
private short sequence;
public static final int CRC = 0x04C5;
public Acknowledge() {
sequence = 0;
private long targetId;
public IntendedTarget(long objectId, long targetId) {
super(objectId, CRC);
setTargetId(targetId);
}
public Acknowledge(ByteBuffer data) {
public IntendedTarget(ByteBuffer data) {
super(CRC);
decode(data);
}
public Acknowledge(short sequence) {
this.sequence = sequence;
}
public void decode(ByteBuffer data) {
if (data.array().length < 4)
return;
data.position(2);
sequence = getNetShort(data);
decodeHeader(data);
targetId = getLong(data);
}
public ByteBuffer encode() {
ByteBuffer data = ByteBuffer.allocate(4);
addNetShort(data, 21);
addNetShort(data, sequence);
ByteBuffer data = ByteBuffer.allocate(HEADER_LENGTH + 2);
encodeHeader(data);
addLong(data, targetId);
return data;
}
public void setSequence(short sequence) { this.sequence = sequence; }
public long getTargetId() { return targetId; }
public short getSequence() { return sequence; }
public void setTargetId(long targetId) { this.targetId = targetId; }
}
@@ -29,6 +29,7 @@ package network.packets.swg.zone.object_controller;
import java.nio.ByteBuffer;
import resources.server_info.Log;
import network.packets.swg.SWGPacket;
public abstract class ObjectController extends SWGPacket {
@@ -88,14 +89,17 @@ public abstract class ObjectController extends SWGPacket {
return null;
int crc = data.getInt(10);
switch (crc) {
case 0x00000071: return new DataTransform(data);
case 0x000000F1: return new DataTransformWithParent(data);
case 0x00000116: return new CommandQueueEnqueue(data);
case 0x00000117: return new CommandQueueDequeue(data);
case 0x0000012E: return new PlayerEmote(data);
case 0x00000131: return new PostureUpdate(data);
case 0x00000146: return new ObjectMenuRequest(data);
case 0x0071: return new DataTransform(data);
case 0x00F1: return new DataTransformWithParent(data);
case 0x0116: return new CommandQueueEnqueue(data);
case 0x0117: return new CommandQueueDequeue(data);
case 0x0126: return null; // Look at target
case 0x012E: return new PlayerEmote(data);
case 0x0131: return new PostureUpdate(data);
case 0x0146: return new ObjectMenuRequest(data);
case 0x04C5: return new IntendedTarget(data);
}
Log.w("ObjectController", "Unknown object controller: %08X", crc);
return null;
}
+51 -28
View File
@@ -30,13 +30,20 @@ package resources;
public class Galaxy {
// Population status values. Values are in percent.
private static final double VERY_LIGHT = 10;
private static final double LIGHT = 20;
private static final double MEDIUM = 30;
private static final double HEAVY = 40;
private static final double VERY_HEAVY = 50;
private static final double EXTREMELY_HEAVY = 100;
private int id = 0;
private String name = "";
private String address = "";
private int zonePort = 44463;
private int pingPort = 44462;
private int population = 0;
private int popStatus = 0;
private GalaxyStatus status = GalaxyStatus.DOWN;
private int timeZone = 0;
private int maxCharacters = 0;
@@ -48,37 +55,53 @@ public class Galaxy {
}
public int getId() { return id; }
public String getName() { return name; }
public String getAddress() { return address; }
public int getZonePort() { return zonePort; }
public int getPingPort() { return pingPort; }
public int getPopulation() { return population; }
public int getPopulationStatus() { return popStatus; }
public GalaxyStatus getStatus() { return status; }
public int getTimeZone() { return timeZone; }
public int getMaxCharacters() { return maxCharacters; }
public int getOnlinePlayerLimit() { return onlinePlayerLimit; }
public int getOnlineFreeTrialLimit() { return onlineFreeTrialLimit; }
public boolean isRecommended() { return recommended; }
public synchronized int getId() { return id; }
public synchronized String getName() { return name; }
public synchronized String getAddress() { return address; }
public synchronized int getZonePort() { return zonePort; }
public synchronized int getPingPort() { return pingPort; }
public synchronized int getPopulation() { return population; }
public synchronized GalaxyStatus getStatus() { return status; }
public synchronized int getTimeZone() { return timeZone; }
public synchronized int getMaxCharacters() { return maxCharacters; }
public synchronized int getOnlinePlayerLimit() { return onlinePlayerLimit; }
public synchronized int getOnlineFreeTrialLimit() { return onlineFreeTrialLimit; }
public synchronized boolean isRecommended() { return recommended; }
public void setId(int id) { this.id = id; }
public void setName(String name) { this.name = name; }
public void setAddress(String addr) { this.address = addr; }
public void setZonePort(int port) { this.zonePort = port; }
public void setPingPort(int port) { this.pingPort = port; }
public void setPopulation(int population) { this.population = population; }
public void setPopulationStatus(int status) { this.popStatus = status; }
public void setStatus(GalaxyStatus status) { this.status = status; }
public void setTimeZone(int timeZone) { this.timeZone = timeZone; }
public void setMaxCharacters(int max) { this.maxCharacters = max; }
public void setOnlinePlayerLimit(int max) { this.onlinePlayerLimit = max; }
public void setOnlineFreeTrialLimit(int max) { this.onlineFreeTrialLimit = max; }
public void setRecommended(boolean r) { this.recommended = r; }
public synchronized int getPopulationStatus() {
if (population < VERY_LIGHT)
return 0;
else if(population < LIGHT)
return 1;
else if(population < MEDIUM)
return 2;
else if(population < HEAVY)
return 3;
else if(population < VERY_HEAVY)
return 4;
else if(population < EXTREMELY_HEAVY)
return 5;
return 6;
}
public synchronized void setId(int id) { this.id = id; }
public synchronized void setName(String name) { this.name = name; }
public synchronized void setAddress(String addr) { this.address = addr; }
public synchronized void setZonePort(int port) { this.zonePort = port; }
public synchronized void setPingPort(int port) { this.pingPort = port; }
public synchronized void setPopulation(int population) { this.population = population; }
public synchronized void setStatus(GalaxyStatus status) { this.status = status; }
public synchronized void setTimeZone(int timeZone) { this.timeZone = timeZone; }
public synchronized void setMaxCharacters(int max) { this.maxCharacters = max; }
public synchronized void setOnlinePlayerLimit(int max) { this.onlinePlayerLimit = max; }
public synchronized void setOnlineFreeTrialLimit(int max) { this.onlineFreeTrialLimit = max; }
public synchronized void setRecommended(boolean r) { this.recommended = r; }
public synchronized void incrementPopulationCount() { population++; }
public synchronized void decrementPopulationCount() { population--; }
public String toString() {
return String.format("Galaxy[ID=%d Name=%s Address=%s Zone=%d Ping=%d Pop=%d PopStat=%d Status=%s Time=%d Max=%d Rec=%b]",
id, name, address, zonePort, pingPort, population, popStatus, status, timeZone, maxCharacters, recommended);
id, name, address, zonePort, pingPort, population, getPopulationStatus(), status, timeZone, maxCharacters, recommended);
}
public void setStatus(int status) {
-77
View File
@@ -1,77 +0,0 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 resources;
import java.util.Collection;
import java.util.LinkedList;
import java.util.ListIterator;
public class SortedLinkedList<E extends Comparable<E>> extends LinkedList<E> {
private static final long serialVersionUID = -6776628467181994889L;
@Override
public boolean add(E e) {
ListIterator<E> iter = super.listIterator();
while (iter.hasNext()) {
if (e.compareTo(iter.next()) <= 0) {
iter.previous();
iter.add(e);
return true;
}
}
super.addLast(e);
return true;
}
@Override
public void add(int index, E element) {
throw new UnsupportedOperationException("The sorted nature of the list prohibits this action.");
}
@Override
public boolean addAll(Collection<? extends E> c) {
for (E item : c) {
add(item);
}
return true;
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
throw new UnsupportedOperationException("The sorted nature of the list prohibits this action.");
}
@Override
public E set(int index, E element) {
throw new UnsupportedOperationException("The sorted nature of the list prohibits this action.");
}
}
+43 -1
View File
@@ -27,14 +27,18 @@
***********************************************************************************/
package resources;
import resources.objects.SWGObject;
import resources.objects.creature.CreatureObject;
import services.galaxy.travel.TravelGroup;
public final class TravelPoint {
public final class TravelPoint implements Comparable<TravelPoint> {
private final String name;
private final Location location;
private final boolean reachable;
private TravelGroup group;
private CreatureObject shuttle;
private SWGObject collector;
private final boolean starport;
public TravelPoint(String name, Location location, boolean starport, boolean reachable) {
@@ -42,6 +46,7 @@ public final class TravelPoint {
this.location = location;
this.starport = starport;
this.reachable = reachable; // Not sure which effect this has on the client.
this.group = null;
}
public String getName() {
@@ -51,6 +56,10 @@ public final class TravelPoint {
public Location getLocation() {
return location;
}
public TravelGroup getGroup() {
return group;
}
public boolean isStarport() {
return starport;
@@ -63,12 +72,45 @@ public final class TravelPoint {
public CreatureObject getShuttle() {
return shuttle;
}
public SWGObject getCollector() {
return collector;
}
public void setShuttle(CreatureObject shuttle) {
this.shuttle = shuttle;
}
public void setCollector(SWGObject collector) {
this.collector = collector;
}
public void setGroup(TravelGroup group) {
this.group = group;
}
public String getSuiFormat() {
return String.format("@planet_n:%s -- %s", location.getTerrain().getName(), name);
}
@Override
public int compareTo(TravelPoint o) {
int comp = location.getTerrain().compareTo(o.getLocation().getTerrain());
if (comp != 0)
return comp;
return name.compareTo(o.getName());
}
@Override
public boolean equals(Object o) {
if (!(o instanceof TravelPoint))
return false;
return name.equals(((TravelPoint) o).getName());
}
@Override
public int hashCode() {
return name.hashCode();
}
}
+9
View File
@@ -13,6 +13,7 @@ public class BuildoutArea implements Comparable<BuildoutArea> {
private double x2;
private double z2;
private boolean adjustCoordinates;
private boolean loaded;
private BuildoutArea() {
@@ -54,6 +55,14 @@ public class BuildoutArea implements Comparable<BuildoutArea> {
return adjustCoordinates;
}
public boolean isLoaded() {
return loaded;
}
public void setLoaded(boolean loaded) {
this.loaded = loaded;
}
public int hashCode() {
return terrain.hashCode() ^ Double.hashCode(x1) ^ Double.hashCode(z1);
}
+4 -15
View File
@@ -28,10 +28,10 @@
package resources.client_info;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
@@ -65,21 +65,10 @@ public class SWGFile {
}
public void read(File file) throws IOException {
FileInputStream inputStream = new FileInputStream(file);
FileChannel channel = inputStream.getChannel();
FileChannel channel = FileChannel.open(file.toPath());
MappedByteBuffer bb = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
int size = (int) channel.size();
ByteBuffer bb = ByteBuffer.allocate((int) channel.size());
if (channel.read(bb) != size) {
System.err.println("Failed to properly read the bytes in file " + file.getAbsolutePath() + "!");
inputStream.close();
return;
} else {
inputStream.close();
}
// Reading will add bytes to the buffer, so we need to flip it before reading the buffer to IffNode's
bb.flip();
channel.close();
master = new IffNode("", true);
currentForm = master;
@@ -1,35 +1,33 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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/>. *
* *
***********************************************************************************/
* Copyright (c) 2015 /// 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 resources.client_info.visitors;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import resources.client_info.ClientData;
@@ -38,49 +36,45 @@ import resources.client_info.SWGFile;
public class CrcStringTableData extends ClientData {
private List<Integer> crcList = new ArrayList<>();
private List<Integer> startList = new ArrayList<>();
private List<String> stringList = new ArrayList<>();
private Map <Integer, String> crcMap = new Hashtable<>(4*1024);
private int count;
private final Map<Integer, String> crcMap = new HashMap<>();
private final Map<String, Integer> reverseCrcMap = new HashMap<>();
@Override
public void readIff(SWGFile iff) {
iff.enterNextForm(); // Version
int [] crcList = null;
int count = 0;
IffNode chunk;
while ((chunk = iff.enterNextChunk()) != null) {
switch(chunk.getTag()) {
switch (chunk.getTag()) {
case "DATA":
count = chunk.readInt();
crcList = new int[count];
break;
case "CRCT":
for(int i=0; i < count; ++i) {
crcList.add(chunk.readUInt());
for (int i = 0; i < count; ++i) {
crcList[i] = chunk.readUInt();
}
break;
case "STRT":
for(int i=0; i < count; ++i) {
startList.add(chunk.readInt());
}
chunk.skip(count * 4); // Start List -- not needed
break;
case "STNG":
for(int i=0; i < count; ++i) {
for (int i = 0; i < count; ++i) {
String str = chunk.readString();
crcMap.put(crcList.get(i), str);
stringList.add(str);
crcMap.put(crcList[i], str);
reverseCrcMap.put(str, crcList[i]);
}
break;
default: break;
default:
break;
}
}
}
public boolean isValidCrc(int crc) {
return crcList.contains(crc);
return reverseCrcMap.containsValue(crc);
}
public String getTemplateString(int crc) {
@@ -88,10 +82,7 @@ public class CrcStringTableData extends ClientData {
}
public int getCrcForString(String str) {
if (stringList.contains(str)) {
return crcList.get(stringList.indexOf(str));
} else {
return 0;
}
Integer crc = reverseCrcMap.get(str);
return crc == null ? 0 : crc.intValue();
}
}
@@ -29,6 +29,7 @@ package resources.client_info.visitors;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
@@ -39,26 +40,106 @@ import resources.client_info.SWGFile;
public class ObjectData extends ClientData {
private final Map<String, Object> attributes = new HashMap<>();
private final Map<ObjectDataAttribute, Object> attributes = new HashMap<>();
private final List<String> parsedFiles = new ArrayList<>();
public static final String APPEARANCE_FILE = "appearanceFilename";
public static final String ARRANGEMENT_FILE = "arrangementDescriptorFilename";
public static final String CONTAINER_TYPE = "containerType";
public static final String VOLUME_LIMIT = "containerVolumeLimit";
public static final String DETAIL_STF = "detailedDescription";
public static final String OBJ_STF = "objectName";
public static final String PORTAL_LAYOUT = "portalLayoutFilename";
public static final String SLOT_DESCRIPTOR = "slotDescriptorFilename";
public enum ObjectDataAttribute {
ACCELERATION ("acceleration"),
ANIMATION_MAP_FILENAME ("animationMapFilename"),
APPEARANCE_FILENAME ("appearanceFilename"),
ARRANGEMENT_DESCRIPTOR_FILENAME ("arrangementDescriptorFilename"),
ATTACK_TYPE ("attackType"),
CAMERA_HEIGHT ("cameraHeight"),
CERTIFICATIONS_REQUIRED ("certificationsRequired"),
CLEAR_FLORA_RADIUS ("clearFloraRadius"),
CLIENT_DATA_FILE ("clientDataFile"),
CLIENT_VISIBILITY_FLAG ("clientVisabilityFlag"),
COLLISION_ACTION_BLOCK_FLAGS ("collisionActionBlockFlags"),
COLLISION_ACTION_FLAGS ("collisionActionFlags"),
COLLISION_ACTION_PASS_FLAGS ("collisionActionPassFlags"),
COLLISION_HEIGHT ("collisionHeight"),
COLLISION_LENGTH ("collisionLength"),
COLLISION_MATERIAL_BLOCK_FLAGS ("collisionMaterialBlockFlags"),
COLLISION_MATERIAL_FLAGS ("collisionMaterialFlags"),
COLLISION_MATERIAL_PASS_FLAGS ("collisionMaterialPassFlags"),
COLLISION_OFFSET_X ("collisionOffsetX"),
COLLISION_OFFSET_Z ("collisionOffsetZ"),
COLLISION_RADIUS ("collisionRadius"),
CONST_STRING_CUSTOMIZATION_VARIABLES ("constStringCustomizationVariables"),
CONTAINER_TYPE ("containerType"),
CONTAINER_VOLUME_LIMIT ("containerVolumeLimit"),
CUSTOMIZATION_VARIABLE_MAPPING ("customizationVariableMapping"),
DETAILED_DESCRIPTION ("detailedDescription"),
FORCE_NO_COLLISION ("forceNoCollision"),
GAME_OBJECT_TYPE ("gameObjectType"),
GENDER ("gender"),
INTERIOR_LAYOUT_FILENAME ("interiorLayoutFileName"),
LOCATION_RESERVATION_RADIUS ("locationReservationRadius"),
LOOK_AT_TEXT ("lookAtText"),
MOVEMENT_DATATABLE ("movementDatatable"),
NICHE ("niche"),
NO_BUILD_RADIUS ("noBuildRadius"),
OBJECT_NAME ("objectName"),
ONLY_VISIBLE_IN_TOOLS ("onlyVisibleInTools"),
PALETTE_COLOR_CUSTOMIZATION_VARIABLES ("paletteColorCustomizationVariables"),
PORTAL_LAYOUT_FILENAME ("portalLayoutFilename"),
POSTURE_ALIGN_TO_TERRAIN ("postureAlignToTerrain"),
RACE ("race"),
RANGED_INT_CUSTOMIZATION_VARIABLES ("rangedIntCustomizationVariables"),
SCALE ("scale"),
SCALE_THRESHOLD_BEFORE_EXTENT_TEST ("scaleThresholdBeforeExtentTest"),
SEND_TO_CLIENT ("sendToClient"),
SLOPE_MOD_ANGLE ("slopeModAngle"),
SLOPE_MOD_PERCENT ("slopeModPercent"),
SLOT_DESCRIPTOR_FILENAME ("slotDescriptorFilename"),
SNAP_TO_TERRAIN ("snapToTerrain"),
SOCKET_DESTINATIONS ("socketDestinations"),
SPECIES ("species"),
SPEED ("speed"),
STEP_HEIGHT ("stepHeight"),
STRUCTURE_FOOTPRINT_FILENAME ("structureFootprintFileName"),
SURFACE_TYPE ("surfaceType"),
SWIM_HEIGHT ("swimHeight"),
TARGETABLE ("targetable"),
TERRAIN_MODIFICATION_FILENAME ("terrainModificationFileName"),
TINT_PALETTE ("tintPalette"),
TURN_RADIUS ("turnRate"),
USE_STRUCTURE_FOOTPRINT_OUTLINE ("useStructureFootprintOutline"),
WARP_TOLERANCE ("warpTolerance"),
WATER_MOD_PERCENT ("waterModPercent"),
WEAPON_EFFECT ("weaponEffect"),
WEAPON_EFFECT_INDEX ("weaponEffectIndex");
private static final Map<String, ObjectDataAttribute> ATTRIBUTES = new Hashtable<>(values().length);
static {
for (ObjectDataAttribute attr : values())
ATTRIBUTES.put(attr.getName(), attr);
}
private final String name;
ObjectDataAttribute(String name) {
this.name = name;
}
public String getName() {
return name;
}
public static ObjectDataAttribute getForName(String name) {
return ATTRIBUTES.get(name);
}
}
public ObjectData() {}
@Override
public void readIff(SWGFile iff) {
while(iff.enterNextForm() != null)
while (iff.enterNextForm() != null)
readNextForm(iff);
}
private void readNextForm(SWGFile iff) {
IffNode next;
while ((next = iff.enterNextForm()) != null) {
@@ -67,13 +148,13 @@ public class ObjectData extends ClientData {
readExtendedAttributes(iff);
else if (tag.contains("0"))
readVersionForm(iff);
else if (!tag.isEmpty()) // More than likely to be a template form
else if (!tag.isEmpty())
readNextForm(iff);
}
iff.exitForm();
}
private void readVersionForm(SWGFile iff) {
IffNode attributeChunk;
while ((attributeChunk = iff.enterChunk("XXXX")) != null) {
@@ -100,73 +181,75 @@ public class ObjectData extends ClientData {
attributes.putAll(((ObjectData)attrData).getAttributes());
parsedFiles.add(file);
iff.exitForm();
}
// Try and parse the attribute to map w/ appropriate Object type.
private void parseAttributeChunk(IffNode chunk) {
String attr = chunk.readString();
String str = chunk.readString();
if (str.isEmpty())
return;
ObjectDataAttribute attr = ObjectDataAttribute.getForName(str);
switch (attr) {
case "appearanceFilename": putString(chunk, attr); break;
case "arrangementDescriptorFilename": putString(chunk,attr); break;
case "containerType": putInt(chunk, attr); break;
case "containerVolumeLimit": putInt(chunk, attr);break;
case "detailedDescription": putStfString(chunk, attr); break;
case "forceNoCollision": putBoolean(chunk, attr); break;
case "gender": putInt(chunk, attr); break;
case "objectName": putStfString(chunk, attr); break;
case "portalLayoutFilename": putString(chunk, attr); break;
case "slotDescriptorFilename": putString(chunk, attr); break;
case "structureFootprintFileName": putString(chunk, attr); break;
case "useStructureFootprintOutline": putBoolean(chunk, attr); break;
default:/*System.out.println("Unknown attribute: " + attr);*/ break;
case APPEARANCE_FILENAME: putString(chunk, attr); break;
case ARRANGEMENT_DESCRIPTOR_FILENAME: putString(chunk,attr); break;
case CONTAINER_TYPE: putInt(chunk, attr); break;
case CONTAINER_VOLUME_LIMIT: putInt(chunk, attr);break;
case DETAILED_DESCRIPTION: putStfString(chunk, attr); break;
case FORCE_NO_COLLISION: putBoolean(chunk, attr); break;
case GENDER: putInt(chunk, attr); break;
case OBJECT_NAME: putStfString(chunk, attr); break;
case PORTAL_LAYOUT_FILENAME: putString(chunk, attr); break;
case SLOT_DESCRIPTOR_FILENAME: putString(chunk, attr); break;
case STRUCTURE_FOOTPRINT_FILENAME: putString(chunk, attr); break;
case TARGETABLE: putBoolean(chunk, attr); break;
case USE_STRUCTURE_FOOTPRINT_OUTLINE: putBoolean(chunk, attr); break;
default: break;
}
}
private void putStfString(IffNode chunk, String attr) {
private void putStfString(IffNode chunk, ObjectDataAttribute attr) {
if (chunk.readByte() == 0)
return;
chunk.readByte();
String stfFile = chunk.readString();
String stfFile = getString(chunk);
if (stfFile.isEmpty())
return;
attributes.put(attr, stfFile + ":" + getString(chunk));
}
private String getString(IffNode chunk) {
chunk.readByte();
return chunk.readString();
}
private void putString(IffNode chunk, ObjectDataAttribute attr) {
if (chunk.readByte() == 0)
return;
String s = chunk.readString();
if (s.isEmpty())
return;
chunk.readByte(); // 0x00, 0x01 (Shows up as well even if stfFile prior data.get() is 0)
String stfName = chunk.readString();
attributes.put(attr, stfFile + ":" + stfName);
attributes.put(attr, s);
}
private void putString(IffNode chunk, String attr) {
if (chunk.readByte() != 0) {
String s = chunk.readString();
if (s.isEmpty())
return;
attributes.put(attr, s);
}
private void putInt(IffNode chunk, ObjectDataAttribute attr) {
if (chunk.readByte() == 0)
return; // This should always be 1 if there is an int (note that 0x20 follows after this even if it's 0)
chunk.readByte(); // 0x20 byte for all it seems, unsure what it means
attributes.put(attr, chunk.readInt());
}
private void putInt(IffNode chunk, String attr) {
if (chunk.readByte() != 0) { // This should always be 1 if there is an int (note that 0x20 follows after this even if it's 0)
chunk.readByte(); // 0x20 byte for all it seems, unsure what it means
attributes.put(attr, chunk.readInt());
}
}
private void putBoolean(IffNode chunk, String attr) {
private void putBoolean(IffNode chunk, ObjectDataAttribute attr) {
attributes.put(attr, (chunk.readByte() == 1));
}
public Object getAttribute(String attribute) {
public Object getAttribute(ObjectDataAttribute attribute) {
return attributes.get(attribute);
}
public Map<String, Object> getAttributes() {
public Map<ObjectDataAttribute, Object> getAttributes() {
return attributes;
}
}
+7
View File
@@ -36,6 +36,8 @@ import resources.player.PlayerState;
import utilities.Encoder;
import utilities.Encoder.StringType;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -93,6 +95,11 @@ public class SWGList<E> extends AbstractList<E> implements Encodable, Serializab
this.strType = strType;
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
updateCount = 0;
}
/**
* Appends the specified element to the end of this list if it doesn't already exist. Once added, the updateCount is incremented by one
* and data for the object is encoded.
@@ -34,6 +34,7 @@ import intents.player.DeleteCharacterIntent;
import resources.Location;
import resources.Terrain;
import resources.commands.ICmdCallback;
import resources.network.DisconnectReason;
import resources.objects.SWGObject;
import resources.objects.building.BuildingObject;
import resources.objects.cell.CellObject;
@@ -56,8 +57,6 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import network.packets.soe.Disconnect.DisconnectReason;
/**
* Created by Waverunner on 8/19/2015
*/
@@ -142,7 +141,7 @@ public class QaToolCmdCallback implements ICmdCallback {
new DeleteCharacterIntent((CreatureObject) target).broadcast();
Player owner = target.getOwner();
if (owner != null)
new CloseConnectionIntent(owner.getConnectionId(), owner.getNetworkId(), DisconnectReason.APPLICATION).broadcast();
new CloseConnectionIntent(owner.getNetworkId(), DisconnectReason.APPLICATION).broadcast();
return;
}
Log.i("QA", "[%s] Requested deletion of object: %s", player.getUsername(), target);
+2 -10
View File
@@ -81,6 +81,7 @@ public abstract class Service implements IntentReceiver {
* @return TRUE if termination was successful, FALSE otherwise
*/
public boolean terminate() {
DataManager.terminate();
IntentManager.getInstance().terminate();
return true;
}
@@ -133,16 +134,7 @@ public abstract class Service implements IntentReceiver {
* @param packets the packet(s) to send
*/
public void sendPacket(final long networkId, final Packet ... packets) {
outboundPacketService.sendPacket(networkId, packets);
}
/**
* Sends all packets that were stored in the buffer via sendPacket()
* @return the number of packets sent (includes SWG packets inside
* multi/data packets)
*/
public int flushPackets() {
return outboundPacketService.flushPackets();
outboundPacketService.send(networkId, packets);
}
/**
+16 -3
View File
@@ -30,7 +30,9 @@ package resources.network;
import network.packets.swg.zone.baselines.Baseline.BaselineType;
import network.packets.swg.zone.deltas.DeltasMessage;
import resources.objects.SWGObject;
import resources.objects.creature.CreatureObject;
import resources.player.Player;
import resources.player.PlayerState;
import utilities.Encoder;
import utilities.Encoder.StringType;
@@ -63,10 +65,21 @@ public class DeltaBuilder {
public void send() {
DeltasMessage message = getBuiltMessage();
boolean sendSelf = true;
if (object instanceof CreatureObject && ((CreatureObject) object).isLoggedInPlayer() && object.getOwner().getPlayerState() != PlayerState.ZONED_IN)
sendSelf = false;
switch(num) {
case 3: object.sendObserversAndSelf(message); break;
case 6: object.sendObserversAndSelf(message); break;
default: object.sendSelf(message); break;
case 3:
case 6:
if (sendSelf)
object.sendObserversAndSelf(message);
else
object.sendObservers(message);
break;
default:
if (sendSelf)
object.sendSelf(message);
break;
}
}
@@ -0,0 +1,9 @@
package resources.network;
public enum DisconnectReason {
TIMEOUT,
OTHER_SIDE_TERMINATED,
APPLICATION,
NEW_CONNECTION_ATTEMPT,
CONNECTION_REFUSED
}
+268
View File
@@ -0,0 +1,268 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 resources.network;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
public class TCPServer {
private final Map<SocketAddress, SocketChannel> sockets;
private final InetAddress addr;
private final int port;
private final int bufferSize;
private ServerSocketChannel channel;
private TCPCallback callback;
private TCPListener listener;
public TCPServer(int port, int bufferSize) {
this(null, port, bufferSize);
}
public TCPServer(InetAddress addr, int port, int bufferSize) {
this.sockets = new HashMap<>();
this.addr = addr;
this.port = port;
this.bufferSize = bufferSize;
this.channel = null;
listener = new TCPListener();
}
public void bind() throws IOException {
channel = ServerSocketChannel.open();
channel.socket().bind(new InetSocketAddress(addr, port));
channel.configureBlocking(false);
listener.start();
}
public SocketChannel connectTo(InetAddress addr, int port) throws IOException {
return connectTo(new InetSocketAddress(addr, port));
}
public SocketChannel connectTo(InetSocketAddress sock) throws IOException {
synchronized (sockets) {
SocketChannel sc = sockets.get(sock);
if (sc == null || (!sc.isConnected() && !sc.isConnectionPending())) {
sc = SocketChannel.open(sock);
sc.configureBlocking(false);
sockets.put(sock, sc);
}
return sc;
}
}
public boolean disconnect(SocketAddress sock) {
synchronized (sockets) {
SocketChannel sc = sockets.get(sock);
sockets.remove(sock);
try {
sc.close();
if (callback != null)
callback.onConnectionDisconnect(sc.socket());
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}
private boolean disconnect(SocketChannel sc) {
try {
return disconnect(sc.getRemoteAddress());
} catch (IOException e) {
return false;
}
}
public boolean close() {
listener.stop();
try {
if (channel != null)
channel.close();
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
public boolean send(InetSocketAddress sock, byte [] data) {
synchronized (sockets) {
SocketChannel sc = sockets.get(sock);
try {
if (sc != null && sc.isConnected()) {
ByteBuffer bb = ByteBuffer.wrap(data);
while (bb.hasRemaining())
sc.write(bb);
return true;
}
} catch (IOException e) {
e.printStackTrace();
disconnect(sc);
}
}
return false;
}
public void setCallback(TCPCallback callback) {
this.callback = callback;
}
public interface TCPCallback {
void onIncomingConnection(Socket s);
void onConnectionDisconnect(Socket s);
void onIncomingData(Socket s, byte [] data);
}
private class TCPListener implements Runnable {
private final ByteBuffer buffer;
private Thread thread;
private boolean running;
public TCPListener() {
buffer = ByteBuffer.allocateDirect(bufferSize);
running = false;
thread = null;
}
public void start() {
running = true;
thread = new Thread(this);
thread.start();
}
public void stop() {
running = false;
if (thread != null)
thread.interrupt();
thread = null;
}
public void run() {
try (Selector selector = setupSelector()) {
while (running) {
try {
selector.select();
processSelectionKeys(selector);
} catch (Exception e) {
e.printStackTrace();
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
break;
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private Selector setupSelector() throws IOException {
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_ACCEPT);
return selector;
}
private void processSelectionKeys(Selector selector) throws ClosedChannelException {
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
if (key.isAcceptable()) {
accept(selector);
} else if (key.isReadable()) {
SelectableChannel selectable = key.channel();
if (selectable instanceof SocketChannel)
read(key, (SocketChannel) selectable);
}
it.remove();
}
}
private void accept(Selector selector) {
try {
SocketChannel sc = channel.accept();
if (sc == null)
return;
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
sockets.put(sc.getRemoteAddress(), sc);
if (callback != null)
callback.onIncomingConnection(sc.socket());
} catch (IOException e) {
e.printStackTrace();
}
}
private void read(SelectionKey key, SocketChannel s) {
try {
buffer.position(0);
buffer.limit(bufferSize);
int n = s.read(buffer);
buffer.flip();
if (n < 0) {
key.cancel();
disconnect(s);
} else if (n > 0) {
ByteBuffer smaller = ByteBuffer.allocate(n);
smaller.put(buffer);
if (callback != null)
callback.onIncomingData(s.socket(), smaller.array());
}
} catch (IOException e) {
if (e.getMessage().toLowerCase(Locale.US).contains("connection reset"))
System.err.println("Connection Reset");
else
e.printStackTrace();
System.err.flush();
key.cancel();
disconnect(s);
}
}
}
}
+95 -94
View File
@@ -40,6 +40,7 @@ import network.packets.swg.zone.object_controller.DataTransformWithParent;
import resources.Location;
import resources.Terrain;
import resources.buildout.BuildoutArea;
import resources.client_info.visitors.ObjectData.ObjectDataAttribute;
import resources.common.CRC;
import resources.containers.ContainerPermissions;
import resources.containers.ContainerResult;
@@ -50,8 +51,8 @@ import resources.network.DeltaBuilder;
import resources.objects.building.BuildingObject;
import resources.objects.creature.CreatureObject;
import resources.player.Player;
import resources.player.PlayerState;
import resources.server_info.Log;
import services.CoreManager;
import utilities.Encoder.StringType;
import java.io.IOException;
@@ -62,6 +63,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -76,14 +78,14 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
private final HashMap <String, SWGObject> slots; // HashMap used for null value support
private final Map<Long, SWGObject> containedObjects;
private final Map <String, String> attributes;
private final Map <String, Object> templateAttributes;
private final Map <ObjectDataAttribute, Object> dataAttributes;
private final BaselineType objectType;
private ContainerPermissions containerPermissions;
private transient Set <SWGObject> objectsAware;
private transient BuildoutArea buildoutArea;
private transient Player owner;
private List <List <String>> arrangement;
private Player owner = null;
private SWGObject parent = null;
private StringId stringId = new StringId("", "");
private StringId detailStringId = new StringId("", "");
@@ -109,8 +111,8 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
this.objectsAware = new HashSet<SWGObject>();
this.slots = new HashMap<>();
this.containedObjects = Collections.synchronizedMap(new HashMap<Long, SWGObject>());
this.attributes = new LinkedHashMap<String, String>();
this.templateAttributes = new HashMap<String, Object>();
this.attributes = new LinkedHashMap<>();
this.dataAttributes = new Hashtable<>();
this.containerPermissions = new DefaultPermissions();
this.objectType = objectType;
}
@@ -120,6 +122,7 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
ois.defaultReadObject();
objectsAware = new HashSet<SWGObject>();
buildoutArea = null;
owner = null;
}
/**
@@ -175,14 +178,17 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
* @return {@link ContainerResult}
*/
public ContainerResult moveToContainer(SWGObject requester, SWGObject container) {
if (!container.hasPermission(requester, ContainerPermissions.Permission.MOVE))
if (!container.hasPermission(requester, ContainerPermissions.Permission.MOVE)) {
Log.w("SWGObject", "No permission 'MOVE' for requestor %s with object %s", requester, this);
return ContainerResult.NO_PERMISSION;
}
// Check if object can fit into container or slots
int arrangementId = container.getArrangementId(this);
if (arrangementId == -1) {
// Item is going to go into the container, so check to see if it'll fit
if (container.getMaxContainerSize() <= container.getContainedObjects().size()) {
Log.w("SWGObject", "Unable to add object to container! Container Full");
return ContainerResult.CONTAINER_FULL;
}
}
@@ -191,7 +197,9 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
// Get a pre-parent-removal list of the observers so we can send create/destroy/update messages
Set<SWGObject> oldObservers = getObservers();
oldObservers.add(this);
Player prevOwner = getOwner();
if (prevOwner != null)
oldObservers.add(prevOwner.getCreatureObject());
// Remove this object from the old parent if one exists
SWGObject oldParent = null;
@@ -204,8 +212,16 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
System.err.println("Failed adding " + this + " to " + container);
// Observer notification
Set<SWGObject> containerObservers = container.getObservers();
containerObservers.add(this);
Player newOwner = getOwner();
Set<SWGObject> containerObservers = getObservers();
if (newOwner != null)
containerObservers.add(newOwner.getCreatureObject());
if (prevOwner != newOwner) {
if (prevOwner != null)
oldObservers.add(prevOwner.getCreatureObject());
if (newOwner != null)
containerObservers.add(newOwner.getCreatureObject());
}
sendUpdatedContainment(oldObservers, containerObservers);
Log.i("Container", "Moved %s from %s to %s", this, oldParent, container);
@@ -318,15 +334,9 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
* Gets the object that occupies the specified slot
* @param slotName
* @return The {@link SWGObject} occupying the slot. Returns null if there is nothing in the slot or it doesn't exist.
* <p>If the slot doesn't exist, then an error is printed as well.</p>
*/
public SWGObject getSlottedObject(String slotName) {
if (hasSlot(slotName))
return slots.get(slotName);
else {
System.err.println(this + " does not contain " + slotName);
return null;
}
return slots.get(slotName);
}
/**
@@ -503,12 +513,12 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
return areaId;
}
public Object getTemplateAttribute(String key) {
return templateAttributes.get(key);
public Object getDataAttribute(ObjectDataAttribute key) {
return dataAttributes.get(key);
}
public void setTemplateAttribute(String key, Object value) {
templateAttributes.put(key, value);
public void setDataAttribute(ObjectDataAttribute key, Object value) {
dataAttributes.put(key, value);
}
public List<List<String>> getArrangement() {
@@ -540,14 +550,12 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
}
public int getMaxContainerSize() {
Object volume = templateAttributes.get("containerVolumeLimit");
if (volume == null)
return 0;
try {
return Integer.parseInt(volume.toString());
} catch (NumberFormatException e) {
Object volume = dataAttributes.get(ObjectDataAttribute.CONTAINER_VOLUME_LIMIT);
if (volume == null) {
Log.w("SWGObject", "Volume is null!");
return 0;
}
return (Integer) volume;
}
public void setBuildout(boolean buildout) {
@@ -635,13 +643,17 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
}
public void clearAware() {
clearAware(true);
}
public void clearAware(boolean updateSelf) {
List<SWGObject> objects;
synchronized (objectsAware) {
objects = new ArrayList<>(objectsAware);
}
for (SWGObject o : objects) {
o.awarenessOutOfRange(this);
awarenessOutOfRange(o);
o.awarenessOutOfRange(this, updateSelf);
awarenessOutOfRange(o, true);
}
}
@@ -656,16 +668,16 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
}
private Set<SWGObject> getObservers(SWGObject childObject) {
return getObserversFromSet(objectsAware, childObject);
return getObserversFromSet(new HashSet<SWGObject>(), childObject);
}
private Set<SWGObject> getObserversFromSet(Set<SWGObject> aware, SWGObject childObject) {
Set<SWGObject> awareExtra;
synchronized (aware) {
synchronized (objectsAware) {
awareExtra = new HashSet<>(aware);
awareExtra.addAll(objectsAware);
}
awareExtra = new HashSet<>(aware);
}
synchronized (objectsAware) {
awareExtra.addAll(objectsAware);
}
if (getParent() == null) {
Set<SWGObject> observers = new HashSet<>();
@@ -759,72 +771,73 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
return;
Set<SWGObject> same = new HashSet<>(oldObservers);
same.retainAll(newObservers);
Set<SWGObject> added = new HashSet<>(newObservers);
added.removeAll(oldObservers);
Set<SWGObject> removed = new HashSet<>(oldObservers);
removed.removeAll(newObservers);
for (SWGObject swgObject : same) {
swgObject.sendSelf(new UpdateContainmentMessage(objectId, parent.getObjectId(), slotArrangement));
swgObject.getOwner().sendPacket(new UpdateContainmentMessage(objectId, parent.getObjectId(), slotArrangement));
}
for (SWGObject swgObject : added) {
if (swgObject.getOwner() != null) {
createObject(swgObject.getOwner());
}
createObject(swgObject.getOwner());
}
for (SWGObject swgObject : removed) {
if (swgObject.getOwner() != null) {
destroyObject(swgObject.getOwner());
}
destroyObject(swgObject.getOwner());
}
}
public void updateObjectAwareness(Set <SWGObject> withinRange) {
Set <SWGObject> outOfRange;
synchronized (objectsAware) {
Set<SWGObject> observers = getObserversFromSet(withinRange, this);
Set <SWGObject> outOfRange = new HashSet<>(objectsAware);
outOfRange.removeAll(withinRange);
outOfRange.removeAll(observers);
for (SWGObject o : outOfRange) {
awarenessOutOfRange(o);
o.awarenessOutOfRange(this);
}
for (SWGObject o : withinRange) {
awarenessInRange(o);
o.awarenessInRange(this);
}
for (SWGObject o : observers) {
awarenessInRange(o);
o.awarenessInRange(this);
}
outOfRange = new HashSet<>(objectsAware);
}
Set<SWGObject> observers = getObserversFromSet(withinRange, this);
outOfRange.removeAll(withinRange);
outOfRange.removeAll(observers);
for (SWGObject o : outOfRange) {
awarenessOutOfRange(o, true);
o.awarenessOutOfRange(this, true);
}
for (SWGObject o : withinRange) {
awarenessInRange(o, true);
o.awarenessInRange(this, true);
}
for (SWGObject o : observers) {
awarenessInRange(o, true);
o.awarenessInRange(this, true);
}
}
protected void awarenessOutOfRange(SWGObject o) {
protected void awarenessOutOfRange(SWGObject o, boolean sendDestroy) {
boolean success = false;
synchronized (objectsAware) {
if (objectsAware.remove(o)) {
Player owner = o.getOwner();
if (owner != null)
destroyObject(owner);
else
destroyObjectObservers(o);
}
success = objectsAware.remove(o);
}
if (success && sendDestroy) {
Player owner = o.getOwner();
if (owner != null)
destroyObject(owner);
else
destroyObjectObservers(o);
}
}
protected void awarenessInRange(SWGObject o) {
protected void awarenessInRange(SWGObject o, boolean sendCreate) {
boolean success = false;
synchronized (objectsAware) {
if (objectsAware.add(o)) {
Player owner = o.getOwner();
if (owner != null)
createObject(owner);
else
createObjectObservers(o);
}
success = objectsAware.add(o);
}
if (success && sendCreate) {
Player owner = o.getOwner();
if (owner != null)
createObject(owner);
else
createObjectObservers(o);
}
}
@@ -897,7 +910,7 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
// Now create the contained objects
for (SWGObject containedObject : containedObjects.values()) {
if (containedObject != null && !sentObjects.contains(containedObject)) {
if (containedObject instanceof CreatureObject && containedObject.hasSlot("ghost") && containedObject.getOwner() == null)
if (containedObject instanceof CreatureObject && ((CreatureObject) containedObject).isLoggedOutPlayer())
continue; // If it's a player, but that's logged out
containedObject.createObject(target);
}
@@ -956,7 +969,7 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
}
public void createBaseline6(Player target, BaselineBuilder bb) {
bb.addInt(target.getGalaxyId()); // 0
bb.addInt(CoreManager.getGalaxyId()); // 0
bb.addObject(detailStringId); // 1
bb.incrementOperandCount(2);
@@ -975,24 +988,12 @@ public abstract class SWGObject implements Serializable, Comparable<SWGObject> {
}
public void sendDelta(int type, int update, Object value) {
}
public final void sendDelta(BaselineType baseline, int type, int update, Object value) {
Player owner = getOwner();
if (owner == null || (owner.getPlayerState() != PlayerState.ZONED_IN))
return;
DeltaBuilder builder = new DeltaBuilder(this, baseline, type, update, value);
DeltaBuilder builder = new DeltaBuilder(this, objectType, type, update, value);
builder.send();
}
public final void sendDelta(BaselineType baseline, int type, int update, Object value, StringType strType) {
Player owner = getOwner();
if (owner == null || (owner.getPlayerState() != PlayerState.ZONED_IN))
return;
DeltaBuilder builder = new DeltaBuilder(this, baseline, type, update, value, strType);
public final void sendDelta(int type, int update, Object value, StringType strType) {
DeltaBuilder builder = new DeltaBuilder(this, objectType, type, update, value, strType);
builder.send();
}
@@ -29,8 +29,8 @@ package resources.objects.building;
import network.packets.swg.zone.baselines.Baseline.BaselineType;
import resources.client_info.ClientFactory;
import resources.client_info.visitors.ObjectData;
import resources.client_info.visitors.PortalLayoutData;
import resources.client_info.visitors.ObjectData.ObjectDataAttribute;
import resources.objects.SWGObject;
import resources.objects.cell.CellObject;
import resources.objects.tangible.TangibleObject;
@@ -84,7 +84,7 @@ public class BuildingObject extends TangibleObject {
if (!added || !(object instanceof CellObject))
return added;
String portalFile = String.valueOf(getTemplateAttribute(ObjectData.PORTAL_LAYOUT));
String portalFile = (String) getDataAttribute(ObjectDataAttribute.PORTAL_LAYOUT_FILENAME);
if (portalFile == null || portalFile.isEmpty())
return true;
@@ -98,6 +98,6 @@ public class BuildingObject extends TangibleObject {
private void populateCellData(CellObject cellObject, PortalLayoutData.Cell cellData) {
cellObject.setCellName(cellData.getName());
// System.out.println(cellObject + " cell name " + cellObject.getCelName());
// System.out.println(cellObject + " cell name " + cellObject.getCellName());
}
}
@@ -28,6 +28,7 @@
package resources.objects.buildouts;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@@ -45,11 +46,11 @@ public class BuildoutLoader {
private static final CrcStringTableData crcTable = (CrcStringTableData) ClientFactory.getInfoFromFile("misc/object_template_crc_string_table.iff");
private final Map <Long, SWGObject> objectTable;
private final List <SWGObject> objects;
private final Map<String, List <SWGObject>> objects;
public BuildoutLoader() {
objectTable = new HashMap<>();
objects = new LinkedList<>();
objects = new Hashtable<String, List<SWGObject>>();
}
public void loadAllBuildouts() {
@@ -63,7 +64,7 @@ public class BuildoutLoader {
if (table.getCell(row, 0).equals(terrain.name().toLowerCase(Locale.ENGLISH))) {
TerrainBuildoutLoader loader = new TerrainBuildoutLoader(crcTable, terrain);
loader.load(row);
objects.addAll(loader.getObjects());
objects.putAll(loader.getObjects());
objectTable.putAll(loader.getObjectTable());
return;
}
@@ -76,7 +77,7 @@ public class BuildoutLoader {
return objectTable;
}
public List <SWGObject> getObjects() {
public Map<String, List <SWGObject>> getObjects() {
return objects;
}
@@ -50,13 +50,13 @@ class TerrainBuildoutLoader {
private final CrcStringTableData crcTable;
private final Terrain terrain;
private final Map <Long, SWGObject> objectTable;
private final List <SWGObject> objects;
private final Map<String, List <SWGObject>> objects;
public TerrainBuildoutLoader(CrcStringTableData crcTable, Terrain terrain) {
this.crcTable = crcTable;
this.terrain = terrain;
this.objectTable = new Hashtable<Long, SWGObject>(12*1024);
this.objects = new LinkedList<SWGObject>();
this.objectTable = new Hashtable<Long, SWGObject>(512);
this.objects = new Hashtable<String, List<SWGObject>>();
}
public void load(int sceneNumber) {
@@ -68,12 +68,11 @@ class TerrainBuildoutLoader {
return objectTable;
}
public List <SWGObject> getObjects() {
public Map<String, List <SWGObject>> getObjects() {
return objects;
}
private void loadAreas(int sceneNumber) {
objects.clear();
String file = BASE_PATH+"areas_"+terrain.getName()+".iff";
DatatableData areaTable = (DatatableData) ClientFactory.getInfoFromFile(file);
for (int row = 0; row < areaTable.getRowCount(); row++) {
@@ -87,6 +86,7 @@ class TerrainBuildoutLoader {
String file = BASE_PATH+terrain.getName()+"/"+area.getName().replace("server", "client")+".iff";
DatatableData areaTable = (DatatableData) ClientFactory.getInfoFromFile(file);
SwgBuildoutRow buildoutRow = new SwgBuildoutRow(area);
objectTable.clear();
for (int row = 0; row < areaTable.getRowCount(); row++) {
buildoutRow.load(areaTable.getRow(row), crcTable);
SWGObject object = createObject(buildoutRow);
@@ -94,7 +94,7 @@ class TerrainBuildoutLoader {
object.setLoadRange(buildoutRow.getRadius());
object.setBuildoutAreaId(area.getIndex());
setCellInformation(object, buildoutRow.getCellIndex());
addObject(object, buildoutRow.getContainerId());
addObject(area.getName(), object, buildoutRow.getContainerId());
updatePermissions(object);
}
}
@@ -107,7 +107,7 @@ class TerrainBuildoutLoader {
return object;
}
private void addObject(SWGObject object, long containerId) {
private void addObject(String areaName, SWGObject object, long containerId) {
objectTable.put(object.getObjectId(), object);
if (containerId != 0) {
SWGObject container = objectTable.get(containerId);
@@ -118,7 +118,12 @@ class TerrainBuildoutLoader {
// objects.add(object);
}
} else {
objects.add(object);
List<SWGObject> list = objects.get(areaName);
if (list == null) {
list = new LinkedList<>();
objects.put(areaName, list);
}
list.add(object);
}
}
@@ -60,8 +60,9 @@ public class CreatureObject extends TangibleObject {
private static final long serialVersionUID = 3L;
private transient GroupInviterData inviterData = new GroupInviterData(0, null, "", 0);
private transient long lastReserveOperation = 0;
private transient GroupInviterData inviterData = new GroupInviterData(0, null, "", 0);
private transient long lastReserveOperation = 0;
private transient long groupId = 0;
private Posture posture = Posture.UPRIGHT;
private Race race = Race.HUMAN;
@@ -98,12 +99,12 @@ public class CreatureObject extends TangibleObject {
private boolean performing = false;
private boolean shownOnRadar = true;
private boolean beast = false;
private long groupId = 0;
private byte factionRank = 0;
private long ownerId = 0;
private int battleFatigue = 0;
private long statesBitmask = 0;
private String currentCity = "";
private long lastTransform = 0;
private HologramColour hologramColour = HologramColour.DEFAULT;
private SWGList<Integer> baseAttributes = new SWGList<Integer>(BaselineType.CREO, 1, 2);
@@ -130,7 +131,10 @@ public class CreatureObject extends TangibleObject {
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
// Transient Variables
inviterData = new GroupInviterData(0, null, "", 0);
lastReserveOperation = 0;
groupId = 0;
}
public void removeEquipment(SWGObject obj) {
@@ -277,14 +281,31 @@ public class CreatureObject extends TangibleObject {
return currentCity;
}
public double getTimeSinceLastTransform() {
return (System.nanoTime()-lastTransform)/1E6;
}
public PlayerObject getPlayerObject() {
return (PlayerObject) (hasSlot("ghost") ? getSlottedObject("ghost") : null);
return (PlayerObject) getSlottedObject("ghost");
}
public boolean isPlayer() {
return getSlottedObject("ghost") != null;
}
public boolean isLoggedInPlayer() {
return getOwner() != null && isPlayer();
}
public boolean isLoggedOutPlayer() {
return getOwner() == null && isPlayer();
}
public void setPosture(Posture posture) {
this.posture = posture;
sendDelta(3, 13, posture.getId());
sendObserversAndSelf(new PostureUpdate(getObjectId(), posture));
if (isPlayer())
sendObserversAndSelf(new PostureUpdate(getObjectId(), posture));
}
public void setRace(Race race) {
@@ -442,6 +463,10 @@ public class CreatureObject extends TangibleObject {
this.currentCity = currentCity;
}
public void updateLastTransformTime() {
lastTransform = System.nanoTime();
}
public String getMoodAnimation() {
return moodAnimation;
}
@@ -939,11 +964,4 @@ public class CreatureObject extends TangibleObject {
super.createBaseline9(target, bb);
}
public void sendDelta(int type, int update, Object value) {
sendDelta(BaselineType.CREO, type, update, value);
}
public void sendDelta(int type, int update, Object value, StringType strType) {
sendDelta(BaselineType.CREO, type, update, value, strType);
}
}
+8 -2
View File
@@ -95,7 +95,7 @@ public class GroupObject extends SWGObject { // Extends INTO or TANO?
groupMembers.sendDeltaMessage(this);
awarenessInRange(object);
awarenessInRange(object, true);
object.setGroupId(getObjectId());
if (object.getLevel() > level)
@@ -107,12 +107,18 @@ public class GroupObject extends SWGObject { // Extends INTO or TANO?
groupMembers.remove(new GroupMember(object.getObjectId(), object.getName()));
object.setGroupId(0);
awarenessOutOfRange(object);
awarenessOutOfRange(object, true);
groupMembers.sendDeltaMessage(this);
}
}
public void updateMember(CreatureObject object) {
if (groupMembers.contains(new GroupMember(object.getObjectId(), object.getName())))
awarenessInRange(object, true);
else awarenessOutOfRange(object, true);
}
public long getLeader() {
return leader;
}
@@ -585,14 +585,6 @@ public class PlayerObject extends IntangibleObject {
bb.incrementOperandCount(31);
}
public void sendDelta(int type, int update, Object value) {
sendDelta(BaselineType.PLAY, type, update, value);
}
public void sendDelta(int type, int update, Object value, StringType strType) {
sendDelta(BaselineType.PLAY, type, update, value, strType);
}
public int getStartPlayTime() {
return startPlayTime;
}
@@ -27,15 +27,14 @@
***********************************************************************************/
package resources.objects.staticobject;
import network.packets.swg.zone.baselines.Baseline.BaselineType;
import resources.objects.SWGObject;
import resources.objects.creature.CreatureObject;
public class StaticObject extends SWGObject {
public class StaticObject extends CreatureObject {
private static final long serialVersionUID = 1L;
public StaticObject(long objectId) {
super(objectId, BaselineType.STAO);
super(objectId);
}
}
+6 -15
View File
@@ -27,8 +27,6 @@
***********************************************************************************/
package resources.player;
import java.io.Serializable;
import network.packets.Packet;
import resources.control.Service;
import resources.objects.SWGObject;
@@ -36,11 +34,9 @@ import resources.objects.creature.CreatureObject;
import resources.objects.player.PlayerObject;
import services.player.PlayerManager;
public class Player implements Serializable, Comparable<Player> {
public class Player implements Comparable<Player> {
private static final long serialVersionUID = 1L;
private transient Service playerManager;
private Service playerManager;
private long networkId;
private PlayerState state = PlayerState.DISCONNECTED;
@@ -51,7 +47,6 @@ public class Player implements Serializable, Comparable<Player> {
private int connectionId = 0;
private AccessLevel accessLevel = AccessLevel.PLAYER;
private int galaxyId = 0;
private String galaxyName = "";
private CreatureObject creatureObject= null;
private long lastInboundMessage = 0;
@@ -101,10 +96,6 @@ public class Player implements Serializable, Comparable<Player> {
this.accessLevel = accessLevel;
}
public void setGalaxyId(int galaxyId) {
this.galaxyId = galaxyId;
}
public void setGalaxyName(String galaxyName) {
this.galaxyName = galaxyName;
}
@@ -151,10 +142,6 @@ public class Player implements Serializable, Comparable<Player> {
return accessLevel;
}
public int getGalaxyId() {
return galaxyId;
}
public String getGalaxyName() {
return galaxyName;
}
@@ -194,6 +181,10 @@ public class Player implements Serializable, Comparable<Player> {
@Override
public int compareTo(Player p) {
if (creatureObject == null)
return p.getCreatureObject() == null ? 0 : -1;
else if (p.getCreatureObject() == null)
return 1;
return creatureObject.compareTo(p.getCreatureObject());
}
+1
View File
@@ -29,6 +29,7 @@ package resources.player;
public enum PlayerEvent {
PE_CONNECTED,
PE_CREATE_CHARACTER,
PE_FIRST_ZONE,
PE_ZONE_IN,
+2 -2
View File
@@ -30,10 +30,10 @@ package resources.player;
public enum PlayerState {
DISCONNECTED,
CONNECTED,
LOGGING_IN,
LOGGED_IN,
ZONING_IN,
ZONED_IN,
LOGGED_OUT
ZONED_IN
}
@@ -135,8 +135,10 @@ public class CachedObjectDatabase<V extends Serializable> extends ObjectDatabase
}
public synchronized boolean load() {
if (!fileExists())
if (!fileExists()) {
Log.e("CachedObjectDatabase", "load() - file '%s' does not exist!", getFile());
return false;
}
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream(getFile()));
@@ -152,6 +154,7 @@ public class CachedObjectDatabase<V extends Serializable> extends ObjectDatabase
} catch (EOFException e) {
loaded = true;
} catch (IOException | ClassNotFoundException | ClassCastException e) {
Log.e("CachedObjectDatabase", "load() - unable to load with error: %s - %s", e.getClass().getSimpleName(), e.getMessage());
System.err.println("CachedObjectDatabase: Unable to load with error: " + e.getClass().getSimpleName() + " - " + e.getMessage());
return false;
} finally {
+26 -8
View File
@@ -39,6 +39,8 @@ import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import resources.config.ConfigFile;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
@@ -49,6 +51,7 @@ public final class ConfigWatcher {
private final WatchService watcher;
private final Map<ConfigFile, Config> configMap;
private final Path directory;
private ExecutorService executor;
private boolean stop;
private static final String CFGPATH = "cfg/";
@@ -62,8 +65,8 @@ public final class ConfigWatcher {
@SuppressWarnings("unchecked")
public void start() {
Thread t = new Thread(() -> {
executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
WatchKey key;
Kind<?> eventKind;
WatchEvent<Path> ev;
@@ -74,8 +77,10 @@ public final class ConfigWatcher {
while (!stop) {
try {
key = watcher.take(); // We're stuck here until a change is made.
} catch (InterruptedException e) {
return;
if (key == null)
break;
} catch (Exception e) {
break;
}
for (WatchEvent<?> event : key.pollEvents()) {
@@ -86,8 +91,10 @@ public final class ConfigWatcher {
// but an OVERFLOW event can
// occur regardless if events
// are lost or discarded.
if (eventKind == OVERFLOW)
if (eventKind == OVERFLOW) {
key.reset();
continue;
}
// The context is the name of the file.
ev = (WatchEvent<Path>) event;
@@ -96,8 +103,10 @@ public final class ConfigWatcher {
cfgFile = ConfigFile.configFileForName(CFGPATH + filename);
cfg = configMap.get(cfgFile);
if(cfg == null)
if(cfg == null) {
key.reset();
continue;
}
Map<String, String> delta = cfg.load();
@@ -113,8 +122,17 @@ public final class ConfigWatcher {
key.reset();
}
}
try {
watcher.close();
} catch (Exception e) {
e.printStackTrace();
}
});
t.start();
}
public void stop() {
stop = true;
if (executor != null)
executor.shutdownNow();
}
}
+21 -3
View File
@@ -31,6 +31,8 @@ import intents.server.ConfigChangedIntent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -45,13 +47,14 @@ public class DataManager implements IntentReceiver {
private static DataManager instance = null;
private Map<ConfigFile, Config> config;
private List<ConfigWatcher> watchers;
private RelationalDatabase localDatabase;
private boolean initialized;
private ConfigWatcher cfgWatcher;
private DataManager() {
initialized = false;
IntentManager.getInstance().registerForIntent(ConfigChangedIntent.TYPE, this);
watchers = new ArrayList<>();
}
private synchronized void initialize() {
@@ -62,6 +65,11 @@ public class DataManager implements IntentReceiver {
initialized = localDatabase.isOnline()
&& localDatabase.isTable("users");
}
private synchronized void shutdown() {
for (ConfigWatcher watcher : watchers)
watcher.stop();
}
private synchronized void initializeConfig() {
config = new ConcurrentHashMap<ConfigFile, Config>();
@@ -74,8 +82,9 @@ public class DataManager implements IntentReceiver {
config.put(file, new Config(f));
}
cfgWatcher = new ConfigWatcher(config);
cfgWatcher.start();
ConfigWatcher watcher = new ConfigWatcher(config);
watcher.start();
watchers.add(watcher);
} catch (IOException e) {
e.printStackTrace();
}
@@ -154,6 +163,15 @@ public class DataManager implements IntentReceiver {
return instance;
}
}
public synchronized static final void terminate() {
synchronized (instanceLock) {
if (instance != null) {
instance.shutdown();
instance = null;
}
}
}
@Override
public void onIntentReceived(Intent i) {
+126 -12
View File
@@ -41,14 +41,16 @@ import resources.control.Service;
public class Log {
private static final DateFormat LOG_FORMAT = new SimpleDateFormat("dd-mm-yy HH:mm:ss.SSS");
private static final Log LOG = new Log("log.txt");
private static final Log LOG = new Log("log.txt", LogLevel.VERBOSE);
private final File file;
private BufferedWriter writer;
private LogLevel level;
private boolean open;
private Log(String filename) {
private Log(String filename, LogLevel level) {
this.file = new File(filename);
this.level = level;
open = false;
}
@@ -72,6 +74,14 @@ public class Log {
}
}
private synchronized void setLevel(LogLevel level) {
this.level = level;
}
private synchronized LogLevel getLevel() {
return level;
}
protected static final void start() {
try {
LOG.open();
@@ -88,15 +98,30 @@ public class Log {
}
}
/**
* Sets the minimum level for logs to be reported. This is according to the
* following order: VERBOSE, DEBUG, INFO, WARNING, ERROR, then ASSERT.
* @param level the minimum log level, inclusively. Default is VERBOSE
*/
public static final void setLogLevel(LogLevel level) {
synchronized (LOG) {
LOG.setLevel(level);
}
}
/**
* Logs the string to the server log file, formatted to display the log
* severity, time, tag and message.
* @param level the log level of this message between INFO and ASSERT
* @param level the log level of this message between VERBOSE and ASSERT
* @param tag the tag to use for the log
* @param str the format string for the log
* @param args the string format arguments, if specified
*/
public static final void log(LogLevel level, String tag, String str, Object ... args) {
synchronized (LOG) {
if (LOG.getLevel().compareTo(level) > 0)
return;
}
String date;
synchronized (LOG_FORMAT) {
date = LOG_FORMAT.format(System.currentTimeMillis());
@@ -114,26 +139,24 @@ public class Log {
/**
* Logs the string to the server log file, formatted to display the log
* severity as INFO, as well as the time, tag and message.
* @param level the log level of this message between INFO and ASSERT
* severity as VERBOSE, as well as the time, tag and message.
* @param tag the tag to use for the log
* @param message the format string for the log
* @param args the string format arguments, if specified
*/
public static final void i(String tag, String message, Object ... args) {
log(LogLevel.INFO, tag, message, args);
public static final void v(String tag, String message, Object ... args) {
log(LogLevel.VERBOSE, tag, message, args);
}
/**
* Logs the string to the server log file, formatted to display the log
* severity as INFO, as well as the time, service name and message.
* @param level the log level of this message between INFO and ASSERT
* severity as VERBOSE, as well as the time, service name and message.
* @param service the service outputting this log info
* @param message the format string for the log
* @param args the string format arguments, if specified
*/
public static final void i(Service service, String message, Object ... args) {
log(LogLevel.INFO, service.getClass().getSimpleName(), message, args);
public static final void v(Service service, String message, Object ... args) {
log(LogLevel.VERBOSE, service.getClass().getSimpleName(), message, args);
}
/**
@@ -158,6 +181,28 @@ public class Log {
log(LogLevel.DEBUG, service.getClass().getSimpleName(), message, args);
}
/**
* Logs the string to the server log file, formatted to display the log
* severity as INFO, as well as the time, tag and message.
* @param tag the tag to use for the log
* @param message the format string for the log
* @param args the string format arguments, if specified
*/
public static final void i(String tag, String message, Object ... args) {
log(LogLevel.INFO, tag, message, args);
}
/**
* Logs the string to the server log file, formatted to display the log
* severity as INFO, as well as the time, service name and message.
* @param service the service outputting this log info
* @param message the format string for the log
* @param args the string format arguments, if specified
*/
public static final void i(Service service, String message, Object ... args) {
log(LogLevel.INFO, service.getClass().getSimpleName(), message, args);
}
/**
* Logs the string to the server log file, formatted to display the log
* severity as WARN, as well as the time, tag and message.
@@ -180,6 +225,26 @@ public class Log {
log(LogLevel.WARN, service.getClass().getSimpleName(), message, args);
}
/**
* Logs the exception to the server log file, formatted to display the log
* severity as WARN, as well as the time, and tag.
* @param tag the tag to use for the log
* @param exception the exception to print
*/
public static final void w(String tag, Exception exception) {
printException(LogLevel.WARN, tag, exception);
}
/**
* Logs the exception to the server log file, formatted to display the log
* severity as WARN, as well as the time, and tag.
* @param service the service outputting this log info
* @param exception the exception to print
*/
public static final void w(Service service, Exception exception) {
printException(LogLevel.WARN, service.getClass().getSimpleName(), exception);
}
/**
* Logs the string to the server log file, formatted to display the log
* severity as ERROR, as well as the time, tag and message.
@@ -202,6 +267,26 @@ public class Log {
log(LogLevel.ERROR, service.getClass().getSimpleName(), message, args);
}
/**
* Logs the exception to the server log file, formatted to display the log
* severity as ERROR, as well as the time, and tag.
* @param tag the tag to use for the log
* @param exception the exception to print
*/
public static final void e(String tag, Exception exception) {
printException(LogLevel.ERROR, tag, exception);
}
/**
* Logs the exception to the server log file, formatted to display the log
* severity as ERROR, as well as the time, and tag.
* @param service the service outputting this log info
* @param exception the exception to print
*/
public static final void e(Service service, Exception exception) {
printException(LogLevel.ERROR, service.getClass().getSimpleName(), exception);
}
/**
* Logs the string to the server log file, formatted to display the log
* severity as ASSERT, as well as the time, tag and message.
@@ -224,9 +309,38 @@ public class Log {
log(LogLevel.ASSERT, service.getClass().getSimpleName(), message, args);
}
/**
* Logs the exception to the server log file, formatted to display the log
* severity as ASSERT, as well as the time, and tag.
* @param tag the tag to use for the log
* @param exception the exception to print
*/
public static final void a(String tag, Exception exception) {
printException(LogLevel.ASSERT, tag, exception);
}
/**
* Logs the exception to the server log file, formatted to display the log
* severity as ASSERT, as well as the time, and tag.
* @param service the service outputting this log info
* @param exception the exception to print
*/
public static final void a(Service service, Exception exception) {
printException(LogLevel.ASSERT, service.getClass().getSimpleName(), exception);
}
private static final void printException(LogLevel level, String tag, Exception exception) {
log(level, tag, "Exception in thread\"%s\" %s: %s", Thread.currentThread().getName(), exception.getClass().getName(), exception.getMessage());
log(level, tag, "Caused by: %s: %s", exception.getClass(), exception.getMessage());
for (StackTraceElement e : exception.getStackTrace()) {
log(level, tag, " " + e.toString());
}
}
public static enum LogLevel {
INFO ('I'),
VERBOSE ('V'),
DEBUG ('D'),
INFO ('I'),
WARN ('W'),
ERROR ('E'),
ASSERT ('A');
+8 -13
View File
@@ -40,7 +40,6 @@ public abstract class ObjectDatabase<V extends Serializable> {
private final File file;
private final ScheduledExecutorService autosaveService;
private final Runnable autosaveRunnable;
public ObjectDatabase(String filename) {
this(filename, TimeUnit.MINUTES.toMillis(5));
@@ -56,13 +55,8 @@ public abstract class ObjectDatabase<V extends Serializable> {
if (autosaveInterval < 60000)
autosaveInterval = 60000;
this.autosaveService = Executors.newSingleThreadScheduledExecutor(ThreadUtilities.newThreadFactory("odb-autosave-"+file.getName()));
this.autosaveRunnable = new Runnable() {
public void run() {
autosavePeriodic();
}
};
// Setup
autosaveService.scheduleAtFixedRate(autosaveRunnable, autosaveInterval, autosaveInterval, TimeUnit.MILLISECONDS);
autosaveService.scheduleAtFixedRate(() -> save(), autosaveInterval, autosaveInterval, TimeUnit.MILLISECONDS);
try {
createFilesAndDirectories();
} catch (IOException e) {
@@ -70,10 +64,6 @@ public abstract class ObjectDatabase<V extends Serializable> {
}
}
private void autosavePeriodic() {
save();
}
private void createFilesAndDirectories() throws IOException {
if (file.exists())
return;
@@ -91,9 +81,14 @@ public abstract class ObjectDatabase<V extends Serializable> {
}
}
public void close() {
save();
public final void close() {
autosaveService.shutdownNow();
try {
autosaveService.awaitTermination(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
save();
}
public final File getFile() {
@@ -144,12 +144,17 @@ public abstract class RelationalDatabase implements Closeable {
public ResultSet executeQuery(String query) {
if (connection == null)
return null;
Statement s = null;
try {
Statement s = connection.createStatement();
s = connection.createStatement();
s.execute(query);
s.closeOnCompletion();
return s.getResultSet();
} catch (SQLException e) {
e.printStackTrace();
if (s != null) {
try { s.close(); } catch (SQLException ex) { }
}
return null;
}
}
@@ -100,11 +100,12 @@ public class RelationalServerData extends RelationalDatabase {
}
}
final String sql = String.format("INSERT INTO %s (%s) VALUES (%s)", table, columnStr, valuesStr);
PreparedStatement statement = prepareStatement(sql);
if (statement == null || params.length < getSqlParameterCount(sql))
return false;
assignParameters(statement, params);
return statement.executeUpdate() > 0;
try (PreparedStatement statement = prepareStatement(sql)) {
if (statement == null || params.length < getSqlParameterCount(sql))
return false;
assignParameters(statement, params);
return statement.executeUpdate() > 0;
}
}
/**
@@ -300,8 +301,9 @@ public class RelationalServerData extends RelationalDatabase {
System.err.println("Could not load record: Types length and data length mismatch. Line: " + line);
return;
}
int column = 0;
try {
for (int i = 0; i < data.length; i++) {
for (int i = 0; i < data.length; i++, column++) {
if (types[i].startsWith("TEXT"))
insert.setString(i+1, data[i]);
else if (types[i].startsWith("REAL"))
@@ -313,7 +315,7 @@ public class RelationalServerData extends RelationalDatabase {
}
insert.addBatch();
} catch (NumberFormatException e) {
System.err.println("Could not load record: Record has invalid data. Line: " + line);
System.err.println("Could not load record: Record has invalid data. Line: " + line + " Column: " + column);
}
}
+44 -139
View File
@@ -27,24 +27,10 @@
***********************************************************************************/
package services;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import network.packets.Packet;
import network.packets.soe.DataChannelA;
import network.packets.soe.MultiPacket;
import network.packets.swg.SWGPacket;
import network.packets.swg.zone.baselines.Baseline;
import network.packets.swg.zone.object_controller.ObjectController;
import intents.network.InboundPacketIntent;
import intents.network.OutboundPacketIntent;
import intents.server.ServerManagementIntent;
import intents.server.ServerStatusIntent;
@@ -55,39 +41,39 @@ import resources.control.Intent;
import resources.control.Manager;
import resources.control.ServerStatus;
import resources.server_info.Config;
import resources.server_info.Log;
import resources.server_info.Log.LogLevel;
import services.admin.OnlineInterfaceService;
import services.galaxy.GalacticManager;
import utilities.ThreadUtilities;
public class CoreManager extends Manager {
private static final int galaxyId = 1;
private static final Galaxy GALAXY = new Galaxy();
private static final int GALAXY_ID = 1;
private final ScheduledExecutorService shutdownService;
private OnlineInterfaceService onlineInterfaceService;
private EngineManager engineManager;
private GalacticManager galacticManager;
private PrintStream packetOutput;
private Galaxy galaxy;
private long startTime;
private boolean shutdownRequested;
private boolean packetDebug;
public CoreManager() {
Config c = getConfig(ConfigFile.PRIMARY);
Log.setLogLevel(LogLevel.valueOf(c.getString("LOG-LEVEL", LogLevel.DEBUG.name())));
setupGalaxy(c);
shutdownService = Executors.newSingleThreadScheduledExecutor(ThreadUtilities.newThreadFactory("core-shutdown-service"));
shutdownRequested = false;
galaxy = getGalaxy();
if (galaxy != null) {
onlineInterfaceService = new OnlineInterfaceService();
engineManager = new EngineManager(galaxy);
galacticManager = new GalacticManager(galaxy);
addChildService(onlineInterfaceService);
addChildService(engineManager);
addChildService(galacticManager);
}
registerForIntent(InboundPacketIntent.TYPE);
onlineInterfaceService = new OnlineInterfaceService();
engineManager = new EngineManager();
galacticManager = new GalacticManager();
addChildService(onlineInterfaceService);
addChildService(engineManager);
addChildService(galacticManager);
registerForIntent(OutboundPacketIntent.TYPE);
registerForIntent(ServerManagementIntent.TYPE);
}
@@ -107,14 +93,19 @@ public class CoreManager extends Manager {
@Override
public boolean initialize() {
startTime = System.nanoTime();
packetDebug = getConfig(ConfigFile.PRIMARY).getBoolean("PACKET-DEBUG", false);
initializePacketOutput();
return galaxy != null && super.initialize();
GALAXY.setStatus(GalaxyStatus.LOADING);
return super.initialize();
}
@Override
public boolean start() {
GALAXY.setStatus(GalaxyStatus.UP);
return super.start();
}
@Override
public boolean stop() {
galaxy.setStatus(GalaxyStatus.LOCKED);
GALAXY.setStatus(GalaxyStatus.LOCKED);
return super.stop();
}
@@ -126,30 +117,10 @@ public class CoreManager extends Manager {
@Override
public void onIntentReceived(Intent i) {
if (packetDebug) {
if (i instanceof InboundPacketIntent) {
InboundPacketIntent in = (InboundPacketIntent) i;
packetOutput.println("IN " + in.getNetworkId() + ":" + in.getServerType());
outputPacket(1, in.getPacket());
} else if (i instanceof OutboundPacketIntent) {
OutboundPacketIntent out = (OutboundPacketIntent) i;
packetOutput.println("OUT " + out.getNetworkId());
outputPacket(1, out.getPacket());
}
}
if (i instanceof ServerManagementIntent)
handleServerManagementIntent((ServerManagementIntent) i);
}
private void initializePacketOutput() {
try {
packetOutput = new PrintStream(new FileOutputStream("packets.txt", false), true, "UTF-8");
} catch (FileNotFoundException | UnsupportedEncodingException e) {
e.printStackTrace();
packetOutput = System.out;
}
}
private void handleServerManagementIntent(ServerManagementIntent i) {
switch(i.getEvent()) {
case SHUTDOWN: initiateShutdownSequence(i); break;
@@ -177,53 +148,7 @@ public class CoreManager extends Manager {
}
public GalaxyStatus getGalaxyStatus() {
return galaxy.getStatus();
}
private void outputPacket(int indent, Packet packet) {
if (packet instanceof DataChannelA) {
for (SWGPacket p : ((DataChannelA) packet).getPackets()) {
for (int i = 0; i < indent; i++)
packetOutput.print(" ");
outputSWG(p);
}
} else if (packet instanceof MultiPacket) {
for (Packet p : ((MultiPacket) packet).getPackets()) {
for (int i = 0; i < indent; i++)
packetOutput.print(" ");
if (p instanceof SWGPacket)
outputSWG((SWGPacket) p);
if (p instanceof DataChannelA)
outputPacket(indent+1, p);
}
} else if (packet instanceof SWGPacket) {
for (int i = 0; i < indent; i++)
packetOutput.print(" ");
outputSWG((SWGPacket) packet);
} else {
for (int i = 0; i < indent; i++)
packetOutput.print(" ");
packetOutput.println(packet.getClass().getSimpleName());
}
}
private void outputSWG(SWGPacket p) {
if (p instanceof Baseline)
outputBaseline((Baseline) p);
else if (p instanceof ObjectController)
outputObjectController((ObjectController) p);
else
packetOutput.println(p.getClass().getSimpleName());
}
private void outputBaseline(Baseline b) {
packetOutput.println("Baseline [" + b.getId() + "] " + b.getType() + " " + b.getNum());
}
private void outputObjectController(ObjectController cont) {
int crc = cont.getControllerCrc();
long id = cont.getObjectId();
packetOutput.println("ObjectController [" + id + "] 0x" + Integer.toHexString(crc));
return GALAXY.getStatus();
}
/**
@@ -234,47 +159,27 @@ public class CoreManager extends Manager {
return (System.nanoTime()-startTime)/1E6;
}
private Galaxy getGalaxy() {
PreparedStatement getGalaxy = getLocalDatabase().prepareStatement("SELECT * FROM galaxies WHERE id = ?");
Config c = getConfig(ConfigFile.PRIMARY);
ResultSet set = null;
try {
getGalaxy.setInt(1, galaxyId);
set = getGalaxy.executeQuery();
if (!set.next()) {
System.err.println("CoreManager: No such galaxy exists with ID " + galaxyId + "!");
return null;
}
Galaxy g = new Galaxy();
g.setId(set.getInt("id"));
g.setName(set.getString("name"));
g.setAddress(set.getString("address"));
g.setPopulation(set.getInt("population"));
g.setTimeZone(set.getInt("timezone"));
g.setZonePort(set.getInt("zone_port"));
g.setPingPort(set.getInt("ping_port"));
g.setStatus(set.getInt("status"));
g.setMaxCharacters(c.getInt("GALAXY-MAX-CHARACTERS", 2));
g.setOnlinePlayerLimit(c.getInt("GALAXY-MAX-ONLINE", 3000));
g.setOnlineFreeTrialLimit(c.getInt("GALAXY-MAX-ONLINE", 3000));
g.setRecommended(true);
return g;
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (set != null) {
try {
set.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return null;
public static Galaxy getGalaxy() {
return GALAXY;
}
public static final int getGalaxyId() {
return galaxyId;
public static int getGalaxyId() {
return GALAXY_ID;
}
private static void setupGalaxy(Config c) {
GALAXY.setId(GALAXY_ID);
GALAXY.setName(c.getString("GALAXY-NAME", "Holocore"));
GALAXY.setAddress("");
GALAXY.setPopulation(0);
GALAXY.setTimeZone(c.getInt("GALAXY-TIMEZONE", -6));
GALAXY.setZonePort(0);
GALAXY.setPingPort(0);
GALAXY.setStatus(GalaxyStatus.DOWN);
GALAXY.setMaxCharacters(c.getInt("GALAXY-MAX-CHARACTERS", 2));
GALAXY.setOnlinePlayerLimit(c.getInt("GALAXY-MAX-ONLINE", 3000));
GALAXY.setOnlineFreeTrialLimit(c.getInt("GALAXY-MAX-ONLINE", 3000));
GALAXY.setRecommended(true);
}
}
+2 -3
View File
@@ -30,7 +30,6 @@ package services;
import java.io.File;
import java.io.IOException;
import resources.Galaxy;
import resources.client_info.ServerFactory;
import resources.config.ConfigFile;
import resources.control.Manager;
@@ -43,8 +42,8 @@ public class EngineManager extends Manager {
private ShutdownService shutdownService;
private NetworkManager networkManager;
public EngineManager(Galaxy galaxy) {
networkManager = new NetworkManager(galaxy);
public EngineManager() {
networkManager = new NetworkManager();
shutdownService = new ShutdownService();
addChildService(networkManager);
@@ -123,7 +123,7 @@ public class OnlineInterfaceService extends Service implements HttpServerCallbac
}
}
if (!socket.isSecure()) {
socket.redirect(new URL("https", httpsServer.getBindAddress().getHostName(), httpsServer.getBindPort(), request.getURI().getPath()).toString());
socket.redirect(new URL(request.getURI().getPath()).toString());
return;
}
handler.handleRequest(socket, request);
@@ -183,10 +183,7 @@ public class OnlineInterfaceService extends Service implements HttpServerCallbac
Log.i(TAG, "[%s] Successfully logged in to online interface", username);
} else {
Log.w(TAG, "[%s] Failed to login to online interface. Incorrect user/pass", username);
socket.redirect(new URL("https", httpsServer.getBindAddress().getHostName(), httpsServer.getBindPort(), "/").toString());
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (SQLException e) {
e.printStackTrace();
+23 -7
View File
@@ -4,6 +4,7 @@ import intents.PlayerEventIntent;
import intents.chat.PersistentMessageIntent;
import intents.network.GalacticPacketIntent;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;
import java.util.LinkedList;
@@ -28,19 +29,22 @@ import resources.server_info.CachedObjectDatabase;
import resources.server_info.ObjectDatabase;
import resources.server_info.RelationalServerData;
import resources.server_info.RelationalServerFactory;
import services.CoreManager;
import services.chat.ChatManager.ChatRange;
import services.chat.ChatManager.ChatType;
import services.player.PlayerManager;
public class ChatMailService extends Service {
private final ObjectDatabase<Mail> mails;
private final RelationalServerData chatLogs;
private final PreparedStatement insertChatLog;
private int maxMailId;
public ChatMailService() {
mails = new CachedObjectDatabase<>("odb/mails.db");
chatLogs = RelationalServerFactory.getServerDatabase("chat/chat_log.db");
insertChatLog = chatLogs.prepareStatement("INSERT INTO chat_log VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
maxMailId = 1;
registerForIntent(GalacticPacketIntent.TYPE);
@@ -89,7 +93,7 @@ public class ChatMailService extends Service {
switch (intent.getEvent()) {
case PE_FIRST_ZONE:
sendPersistentMessageHeaders(player, intent.getGalaxy());
sendPersistentMessageHeaders(player);
break;
default:
break;
@@ -104,7 +108,7 @@ public class ChatMailService extends Service {
if (!(p instanceof SWGPacket))
return;
SWGPacket swg = (SWGPacket) p;
String galaxyName = intent.getGalaxy().getName();
String galaxyName = CoreManager.getGalaxy().getName();
switch (swg.getPacketType()) {
/* Mails */
case CHAT_PERSISTENT_MESSAGE_TO_SERVER:
@@ -144,7 +148,7 @@ public class ChatMailService extends Service {
if (result != ChatResult.SUCCESS)
return;
Mail mail = new Mail(sender.getCharacterName().split(" ")[0].toLowerCase(), request.getSubject(), request.getMessage(), recId);
Mail mail = new Mail(sender.getCharacterName().split(" ")[0].toLowerCase(Locale.US), request.getSubject(), request.getMessage(), recId);
mail.setId(maxMailId++);
mail.setTimestamp((int) (new Date().getTime() / 1000));
mail.setOutOfBandPackage(request.getOutOfBandPackage());
@@ -190,7 +194,7 @@ public class ChatMailService extends Service {
sendPersistentMessage(player, mail, MailFlagType.FULL_MESSAGE, galaxy);
}
private void sendPersistentMessageHeaders(Player player, String galaxy) {
private void sendPersistentMessageHeaders(Player player) {
if (player == null || player.getCreatureObject() == null)
return;
@@ -202,6 +206,7 @@ public class ChatMailService extends Service {
playersMail.add(element);
});
String galaxy = CoreManager.getGalaxy().getName();
for (Mail mail : playersMail)
sendPersistentMessage(player, mail, MailFlagType.HEADER_ONLY, galaxy);
}
@@ -236,8 +241,19 @@ public class ChatMailService extends Service {
private void logChat(long sendId, String sendName, long recvId, String recvName, String subject, String message) {
try {
long time = System.currentTimeMillis();
chatLogs.insert("chat_log", null, time, sendId, sendName, recvId, recvName, ChatType.MAIL.name(), ChatRange.PERSONAL.name(), "", subject, message);
synchronized (insertChatLog) {
insertChatLog.setLong(1, System.currentTimeMillis());
insertChatLog.setLong(2, sendId);
insertChatLog.setString(3, sendName);
insertChatLog.setLong(4, recvId);
insertChatLog.setString(5, recvName);
insertChatLog.setString(6, ChatType.MAIL.name());
insertChatLog.setString(7, ChatRange.PERSONAL.name());
insertChatLog.setString(8, "");
insertChatLog.setString(9, subject);
insertChatLog.setString(10, message);
insertChatLog.executeUpdate();
}
} catch (SQLException e) {
e.printStackTrace();
}
+18 -5
View File
@@ -41,7 +41,6 @@ import network.packets.swg.SWGPacket;
import network.packets.swg.zone.chat.*;
import network.packets.swg.zone.chat.ChatSystemMessage.SystemChatType;
import network.packets.swg.zone.object_controller.SpatialChat;
import resources.Galaxy;
import resources.Terrain;
import resources.chat.ChatAvatar;
import resources.chat.ChatResult;
@@ -58,6 +57,7 @@ import resources.server_info.RelationalServerData;
import resources.server_info.RelationalServerFactory;
import services.player.PlayerManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Locale;
@@ -66,11 +66,13 @@ public class ChatManager extends Manager {
private final ChatRoomService roomService;
private final ChatMailService mailService;
private final RelationalServerData chatLogs;
private final PreparedStatement insertChatLog;
public ChatManager(Galaxy g) {
roomService = new ChatRoomService(g);
public ChatManager() {
roomService = new ChatRoomService();
mailService = new ChatMailService();
chatLogs = RelationalServerFactory.getServerDatabase("chat/chat_log.db");
insertChatLog = chatLogs.prepareStatement("INSERT INTO chat_log VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
addChildService(roomService);
addChildService(mailService);
@@ -451,8 +453,19 @@ public class ChatManager extends Manager {
if (message == null)
return;
try {
long time = System.currentTimeMillis();
chatLogs.insert("chat_log", null, time, sendId, sendName, recvId, recvName, type, range, room, subject, message);
synchronized (insertChatLog) {
insertChatLog.setLong(1, System.currentTimeMillis());
insertChatLog.setLong(2, sendId);
insertChatLog.setString(3, sendName);
insertChatLog.setLong(4, recvId);
insertChatLog.setString(5, recvName);
insertChatLog.setString(6, type);
insertChatLog.setString(7, range);
insertChatLog.setString(8, room);
insertChatLog.setString(9, subject);
insertChatLog.setString(10, message);
insertChatLog.executeUpdate();
}
} catch (SQLException e) {
e.printStackTrace();
}
+30 -10
View File
@@ -62,7 +62,6 @@ import network.packets.swg.zone.chat.ChatSendToRoom;
import network.packets.swg.zone.chat.ChatUnbanAvatarFromRoom;
import network.packets.swg.zone.chat.ChatUninviteFromRoom;
import network.packets.swg.zone.insertion.ChatRoomList;
import resources.Galaxy;
import resources.Terrain;
import resources.chat.ChatAvatar;
import resources.chat.ChatResult;
@@ -78,10 +77,12 @@ import resources.server_info.CachedObjectDatabase;
import resources.server_info.ObjectDatabase;
import resources.server_info.RelationalServerData;
import resources.server_info.RelationalServerFactory;
import services.CoreManager;
import services.chat.ChatManager.ChatRange;
import services.chat.ChatManager.ChatType;
import services.player.PlayerManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -98,15 +99,15 @@ public class ChatRoomService extends Service {
private final ObjectDatabase<ChatRoom> database;
private final Map<Integer, ChatRoom> roomMap;
private final RelationalServerData chatLogs;
private final Galaxy galaxy;
private final PreparedStatement insertChatLog;
private int maxChatRoomId;
public ChatRoomService(Galaxy g) {
galaxy = g;
public ChatRoomService() {
database = new CachedObjectDatabase<>("odb/chat_rooms.db");
roomMap = new ConcurrentHashMap<>();
messages = new ConcurrentHashMap<>();
chatLogs = RelationalServerFactory.getServerDatabase("chat/chat_log.db");
insertChatLog = chatLogs.prepareStatement("INSERT INTO chat_log VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
maxChatRoomId = 1;
registerForIntent(ChatRoomUpdateIntent.TYPE);
@@ -123,18 +124,26 @@ public class ChatRoomService extends Service {
roomMap.put(room.getId(), room);
});
createSystemChannels(galaxy.getName());
createSystemChannels(CoreManager.getGalaxy().getName());
return super.initialize();
}
@Override
public boolean terminate() {
database.close();
return super.terminate();
}
@Override
public void onIntentReceived(Intent i) {
switch(i.getType()) {
case ChatRoomUpdateIntent.TYPE:
processChatRoomUpdateIntent((ChatRoomUpdateIntent) i);
if (i instanceof ChatRoomUpdateIntent)
processChatRoomUpdateIntent((ChatRoomUpdateIntent) i);
break;
case GalacticPacketIntent.TYPE:
processPacket((GalacticPacketIntent) i);
if (i instanceof GalacticPacketIntent)
processPacket((GalacticPacketIntent) i);
break;
case PlayerEventIntent.TYPE:
if (i instanceof PlayerEventIntent)
@@ -704,7 +713,7 @@ public class ChatRoomService extends Service {
return getRoom(path);
// All paths should have parents, lets validate to make sure they exist first. Create them if they don't.
int lastIndex = path.lastIndexOf(".");
int lastIndex = path.lastIndexOf('.');
if (lastIndex != -1) {
String parentPath = path.substring(0, lastIndex);
if (getRoom(parentPath) == null) {
@@ -835,8 +844,19 @@ public class ChatRoomService extends Service {
private void logChat(long sendId, String sendName, String room, String message) {
try {
long time = System.currentTimeMillis();
chatLogs.insert("chat_log", null, time, sendId, sendName, 0, "", ChatType.CHAT.name(), ChatRange.ROOM.name(), room, "", message);
synchronized (insertChatLog) {
insertChatLog.setLong(1, System.currentTimeMillis());
insertChatLog.setLong(2, sendId);
insertChatLog.setString(3, sendName);
insertChatLog.setLong(4, 0);
insertChatLog.setString(5, "");
insertChatLog.setString(6, ChatType.CHAT.name());
insertChatLog.setString(7, ChatRange.ROOM.name());
insertChatLog.setString(8, room);
insertChatLog.setString(9, "");
insertChatLog.setString(10, message);
insertChatLog.executeUpdate();
}
} catch (SQLException e) {
e.printStackTrace();
}
+25 -89
View File
@@ -33,8 +33,6 @@ import intents.network.ForceDisconnectIntent;
import intents.network.GalacticPacketIntent;
import intents.player.ZonePlayerSwapIntent;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
@@ -43,12 +41,10 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import main.ProjectSWG;
import network.packets.soe.Disconnect;
import network.packets.soe.Disconnect.DisconnectReason;
import network.packets.swg.zone.HeartBeat;
import resources.control.Intent;
import resources.control.Service;
import resources.network.DisconnectReason;
import resources.objects.creature.CreatureObject;
import resources.objects.player.PlayerObject;
import resources.player.Player;
@@ -56,43 +52,23 @@ import resources.player.PlayerEvent;
import resources.player.PlayerFlags;
import resources.player.PlayerState;
import resources.server_info.Log;
import services.CoreManager;
import utilities.DebugUtilities;
import utilities.ThreadUtilities;
public class ConnectionService extends Service {
private static final double LD_THRESHOLD = TimeUnit.MINUTES.toMillis(3); // Time since last packet
private static final double DISAPPEAR_THRESHOLD = TimeUnit.MINUTES.toMillis(2); // Time after the LD
private static final String INCREMENT_POPULATION_SQL = "UPDATE galaxies SET population = population + 1 WHERE id = ?";
private static final String DECREMENT_POPULATION_SQL = "UPDATE galaxies SET population = population - 1 WHERE id = ?";
private static final double DISAPPEAR_THRESHOLD = TimeUnit.MINUTES.toMillis(3); // Time after the LD
private final ScheduledExecutorService updateService;
private final Runnable updateRunnable;
private final Runnable disappearRunnable;
private final Set <DisappearPlayer> disappearPlayers;
private final Set <Player> zonedInPlayers;
private PreparedStatement incrementPopulation;
private PreparedStatement decrementPopulation;
public ConnectionService() {
updateService = Executors.newSingleThreadScheduledExecutor(ThreadUtilities.newThreadFactory("conn-update-service"));
zonedInPlayers = new LinkedHashSet<Player>();
disappearPlayers = new HashSet<DisappearPlayer>();
updateRunnable = new Runnable() {
public void run() {
synchronized (zonedInPlayers) {
Iterator<Player> i = zonedInPlayers.iterator();
while (i.hasNext()) {
Player p = i.next();
if (p.getTimeSinceLastPacket() > LD_THRESHOLD) {
i.remove();
logOut(p);
disconnect(p, DisconnectReason.TIMEOUT);
}
}
}
}
};
disappearRunnable = new Runnable() {
public void run() {
synchronized (disappearPlayers) {
@@ -100,7 +76,8 @@ public class ConnectionService extends Service {
while (iter.hasNext()) {
DisappearPlayer p = iter.next();
if ((System.nanoTime()-p.getTime())/1E6 >= DISAPPEAR_THRESHOLD) {
disappear(p.getPlayer(), DisconnectReason.TIMEOUT);
DebugUtilities.printPlayerCharacterDebug(ConnectionService.this, p.getPlayer(), "Disappearing");
disappear(p.getPlayer(), false, DisconnectReason.APPLICATION);
iter.remove();
}
}
@@ -114,16 +91,8 @@ public class ConnectionService extends Service {
registerForIntent(ZonePlayerSwapIntent.TYPE);
}
@Override
public boolean initialize() {
incrementPopulation = getLocalDatabase().prepareStatement(INCREMENT_POPULATION_SQL);
decrementPopulation = getLocalDatabase().prepareStatement(DECREMENT_POPULATION_SQL);
return super.initialize();
}
@Override
public boolean start() {
updateService.scheduleAtFixedRate(updateRunnable, 10, 10, TimeUnit.SECONDS);
return super.start();
}
@@ -155,15 +124,8 @@ public class ConnectionService extends Service {
switch (pei.getEvent()) {
case PE_FIRST_ZONE: {
Player p = pei.getPlayer();
try {
synchronized (incrementPopulation) {
incrementPopulation.setInt(1, ProjectSWG.getGalaxyId());
incrementPopulation.executeUpdate();
}
} catch (SQLException e) {
Log.e("ConnectionService", "SQLException occured when trying to increase population value.");
e.printStackTrace();
}
CoreManager.getGalaxy().incrementPopulationCount();
removeFromLists(p);
synchronized (zonedInPlayers) {
zonedInPlayers.add(p);
}
@@ -173,16 +135,9 @@ public class ConnectionService extends Service {
clearPlayerFlag(pei.getPlayer(), pei.getEvent(), PlayerFlags.LD);
break;
case PE_LOGGED_OUT:
try {
synchronized (decrementPopulation) {
decrementPopulation.setInt(1, ProjectSWG.getGalaxyId());
decrementPopulation.executeUpdate();
}
} catch (SQLException e) {
Log.e("ConnectionService", "SQLException occured when trying to decrease population value.");
e.printStackTrace();
}
CoreManager.getGalaxy().decrementPopulationCount();
setPlayerFlag(pei.getPlayer(), pei.getEvent(), PlayerFlags.LD);
logOut(pei.getPlayer(), true);
break;
default:
break;
@@ -190,20 +145,11 @@ public class ConnectionService extends Service {
}
private void onGalacticPacketIntent(GalacticPacketIntent gpi) {
if (gpi.getPacket() instanceof HeartBeat) {
Player p = gpi.getPlayerManager().getPlayerFromNetworkId(gpi.getNetworkId());
if (p != null)
Player p = gpi.getPlayerManager().getPlayerFromNetworkId(gpi.getNetworkId());
if (p != null) {
p.updateLastPacketTimestamp();
if (gpi.getPacket() instanceof HeartBeat)
p.sendPacket(gpi.getPacket());
} else if (gpi.getPacket() instanceof Disconnect) {
Player p = gpi.getPlayerManager().getPlayerFromNetworkId(gpi.getNetworkId());
if (p != null) {
if (p.getPlayerState() != PlayerState.DISCONNECTED) {
logOut(p);
disconnect(p, DisconnectReason.TIMEOUT);
} else {
disconnect(p, DisconnectReason.OTHER_SIDE_TERMINATED);
}
}
}
}
@@ -211,7 +157,7 @@ public class ConnectionService extends Service {
logOut(fdi.getPlayer(), !fdi.getDisappearImmediately());
disconnect(fdi.getPlayer(), fdi.getDisconnectReason());
if (fdi.getDisappearImmediately())
disappear(fdi.getPlayer(), fdi.getDisconnectReason());
disappear(fdi.getPlayer(), fdi.getDisappearImmediately(), fdi.getDisconnectReason());
}
private void onZonePlayerSwapIntent(ZonePlayerSwapIntent zpsi) {
@@ -221,9 +167,9 @@ public class ConnectionService extends Service {
removeFromLists(before);
updatePlayTime(before);
Log.i("ConnectionService", "Logged out %s with character %s", before.getUsername(), before.getCharacterName());
new PlayerEventIntent(before, before.getGalaxyName(), PlayerEvent.PE_LOGGED_OUT).broadcast();
new PlayerEventIntent(before, PlayerEvent.PE_LOGGED_OUT).broadcast();
Log.i("ConnectionService", "Disconnected %s with character %s and reason: %s", before.getUsername(), before.getCharacterName(), DisconnectReason.NEW_CONNECTION_ATTEMPT);
new CloseConnectionIntent(before.getConnectionId(), before.getNetworkId(), DisconnectReason.NEW_CONNECTION_ATTEMPT).broadcast();
new CloseConnectionIntent(before.getNetworkId(), DisconnectReason.NEW_CONNECTION_ATTEMPT).broadcast();
before.setPlayerState(PlayerState.DISCONNECTED);
creature.setOwner(after);
}
@@ -277,17 +223,11 @@ public class ConnectionService extends Service {
return player;
}
private void logOut(Player p) {
logOut(p, true);
}
private void logOut(Player p, boolean addToDisappear) {
System.out.println("[" + p.getUsername() +"] Logged out " + p.getCharacterName());
Log.i("ConnectionService", "Logged out %s with character %s", p.getUsername(), p.getCharacterName());
removeFromLists(p);
updatePlayTime(p);
p.setPlayerState(PlayerState.LOGGED_OUT);
new PlayerEventIntent(p, p.getGalaxyName(), PlayerEvent.PE_LOGGED_OUT).broadcast();
if (addToDisappear) {
synchronized (disappearPlayers) {
disappearPlayers.add(new DisappearPlayer(System.nanoTime(), p));
@@ -296,25 +236,21 @@ public class ConnectionService extends Service {
}
}
private void disappear(Player p, DisconnectReason reason) {
private void disappear(Player p, boolean newConnection, DisconnectReason reason) {
System.out.println("[" + p.getUsername() +"] " + p.getCharacterName() + " disappeared");
Log.i("ConnectionService", "Disappeared %s with character %s", p.getUsername(), p.getCharacterName());
Log.i("ConnectionService", "Disappeared %s with character %s with reason %s", p.getUsername(), p.getCharacterName(), reason);
switch(reason) {
case NEW_CONNECTION_ATTEMPT: // The player is attempting to re-zone
removeFromDisappear(p);
break;
default:
removeFromLists(p);
break;
}
if (newConnection) // Attempting to re-zone
removeFromDisappear(p);
else
removeFromLists(p);
p.setPlayerState(PlayerState.DISCONNECTED);
new PlayerEventIntent(p, PlayerEvent.PE_DISAPPEAR).broadcast();
}
private void disconnect(Player player, DisconnectReason reason) {
Log.i("ConnectionService", "Disconnected %s with character %s and reason: %s", player.getUsername(), player.getCharacterName(), reason);
new CloseConnectionIntent(player.getConnectionId(), player.getNetworkId(), reason).broadcast();
Log.i("ConnectionService", "Disconnected %s with character %s with reason %s", player.getUsername(), player.getCharacterName(), reason);
new CloseConnectionIntent(player.getNetworkId(), reason).broadcast();
}
private void updatePlayTime(Player p) {
@@ -84,6 +84,17 @@ public final class EnvironmentService extends Service {
return super.start();
}
@Override
public boolean stop() {
executor.shutdownNow();
try {
executor.awaitTermination(3000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
}
return super.stop();
}
@Override
public void onIntentReceived(Intent i) {
if(i.getType().equals(PlayerEventIntent.TYPE))
+27 -57
View File
@@ -27,43 +27,37 @@
***********************************************************************************/
package services.galaxy;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Map;
import intents.GalacticIntent;
import intents.network.ConnectionClosedIntent;
import intents.network.ConnectionOpenedIntent;
import intents.network.GalacticPacketIntent;
import intents.network.InboundPacketIntent;
import resources.Galaxy;
import resources.control.Intent;
import resources.control.Manager;
import resources.server_info.DataManager;
import resources.server_info.Log;
import resources.server_info.RelationalDatabase;
import services.CoreManager;
import services.chat.ChatManager;
import services.galaxy.travel.TravelService;
import services.objects.ObjectManager;
import services.player.PlayerManager;
public class GalacticManager extends Manager {
private final Object prevPacketIntentMutex = new Object();
private final static String resetPopulationSQL = "UPDATE galaxies SET population = 0 WHERE id = ?";
private ObjectManager objectManager;
private PlayerManager playerManager;
private GameManager gameManager;
private ChatManager chatManager;
private final ObjectManager objectManager;
private final PlayerManager playerManager;
private final GameManager gameManager;
private final ChatManager chatManager;
private final TravelService travelService;
private Intent prevPacketIntent;
private Galaxy galaxy;
private final Map<Long, Intent> prevIntentMap;
public GalacticManager(Galaxy g) {
this.galaxy = g;
public GalacticManager() {
objectManager = new ObjectManager();
playerManager = new PlayerManager();
gameManager = new GameManager();
chatManager = new ChatManager(g);
chatManager = new ChatManager();
travelService = new TravelService(objectManager);
prevPacketIntent = null;
prevIntentMap = new Hashtable<>();
addChildService(objectManager);
addChildService(playerManager);
@@ -72,6 +66,8 @@ public class GalacticManager extends Manager {
addChildService(travelService);
registerForIntent(InboundPacketIntent.TYPE);
registerForIntent(ConnectionOpenedIntent.TYPE);
registerForIntent(ConnectionClosedIntent.TYPE);
}
@Override
@@ -83,32 +79,17 @@ public class GalacticManager extends Manager {
@Override
public void onIntentReceived(Intent i) {
if (i instanceof InboundPacketIntent) {
synchronized (prevPacketIntentMutex) {
GalacticPacketIntent g = new GalacticPacketIntent((InboundPacketIntent) i);
if (prevPacketIntent == null)
broadcastGalacticIntent(g);
else
broadcastGalacticIntentAfterIntent(g, i);
prevPacketIntent = g;
long networkId = ((InboundPacketIntent) i).getNetworkId();
GalacticPacketIntent g = new GalacticPacketIntent((InboundPacketIntent) i);
g.setGalacticManager(this);
synchronized (prevIntentMap) {
g.broadcastAfterIntent(prevIntentMap.get(networkId));
prevIntentMap.put(networkId, g);
}
} else if (i instanceof ConnectionClosedIntent) {
synchronized (prevIntentMap) {
prevIntentMap.remove(((ConnectionClosedIntent) i).getNetworkId());
}
}
}
public void broadcastGalacticIntent(GalacticIntent i) {
synchronized (i) {
if (i.isBroadcasted())
return;
prepareGalacticIntent(i);
i.broadcast();
}
}
public void broadcastGalacticIntentAfterIntent(GalacticIntent g, Intent i) {
synchronized (g) {
if (g.isBroadcasted())
return;
prepareGalacticIntent(g);
g.broadcastAfterIntent(i);
}
}
@@ -120,19 +101,8 @@ public class GalacticManager extends Manager {
return playerManager;
}
private void prepareGalacticIntent(GalacticIntent i) {
i.setGalacticManager(this);
i.setGalaxy(galaxy);
}
private void resetPopulationCount() {
RelationalDatabase db = DataManager.getInstance().getLocalDatabase();
try(PreparedStatement resetPopulation = db.prepareStatement(GalacticManager.resetPopulationSQL)) {
resetPopulation.setInt(1, galaxy.getId());
resetPopulation.executeUpdate();
} catch (SQLException e) {
Log.e("ProjectSWG", "SQLException occured when trying to reset population value.");
e.printStackTrace();
}
CoreManager.getGalaxy().setPopulation(0);
}
}
@@ -1,5 +1,6 @@
package services.galaxy.terminals;
import intents.radial.ObjectClickedIntent;
import intents.radial.RadialRegisterIntent;
import intents.radial.RadialRequestIntent;
import intents.radial.RadialResponseIntent;
@@ -14,6 +15,7 @@ import java.util.Set;
import resources.control.Intent;
import resources.control.Service;
import resources.radial.RadialItem;
import resources.radial.RadialOption;
import resources.radial.Radials;
import resources.server_info.Log;
@@ -41,6 +43,7 @@ public class TerminalService extends Service {
registerForIntent(RadialRequestIntent.TYPE);
registerForIntent(RadialSelectionIntent.TYPE);
registerForIntent(ObjectClickedIntent.TYPE);
}
@Override
@@ -93,6 +96,19 @@ public class TerminalService extends Service {
Radials.handleSelection(script, rsi.getPlayer(), rsi.getTarget(), rsi.getSelection());
}
break;
case ObjectClickedIntent.TYPE:
if (i instanceof ObjectClickedIntent) {
ObjectClickedIntent oci = (ObjectClickedIntent) i;
String script = lookupScript(oci.getTarget().getTemplate());
if (script == null)
return;
List<RadialOption> options = Radials.getRadialOptions(script, oci.getRequestor().getOwner(), oci.getTarget());
if (options.isEmpty())
return;
RadialItem item = RadialItem.getFromId(options.get(0).getId());
Radials.handleSelection(script, oci.getRequestor().getOwner(), oci.getTarget(), item);
}
break;
}
}
+187
View File
@@ -0,0 +1,187 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 services.galaxy.travel;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import resources.Location;
import resources.Posture;
import resources.Terrain;
import resources.TravelPoint;
import resources.objects.creature.CreatureObject;
public class TravelGroup implements Runnable {
private final Set<TravelPoint> points;
private final Map<Terrain, Set<TravelPoint>> terrainToPoint;
private final AtomicLong timeRemaining;
private final String template;
private final long landTime;
private final long groundTime;
private final long airTime;
private final boolean starport;
private ShuttleStatus status;
public TravelGroup(String template, long landTime, long groundTime, long airTime) {
this.points = new HashSet<>();
this.terrainToPoint = new HashMap<>();
this.timeRemaining = new AtomicLong(airTime / 1000);
this.template = template;
this.landTime = landTime + 10000;
this.groundTime = groundTime;
this.airTime = airTime;
this.starport = template.endsWith("shared_player_transport.iff");
this.status = ShuttleStatus.GROUNDED;
}
public void addTravelPoint(TravelPoint point) {
point.setGroup(this);
synchronized (points) {
points.add(point);
}
synchronized (terrainToPoint) {
Terrain t = point.getLocation().getTerrain();
Set<TravelPoint> s = terrainToPoint.get(t);
if (s == null) {
s = new HashSet<>();
terrainToPoint.put(t, s);
}
s.add(point);
}
}
public void getPointsForTerrain(Collection<TravelPoint> points, TravelPoint nearest, Terrain to) {
synchronized (terrainToPoint) {
Set<TravelPoint> set = terrainToPoint.get(to);
if (set == null)
return;
if (nearest.getLocation().getTerrain() == to)
points.addAll(set);
else if (nearest.isStarport() && starport)
points.addAll(set);
}
}
public TravelPoint getNearestPoint(Location l) {
synchronized (terrainToPoint) {
Set<TravelPoint> set = terrainToPoint.get(l.getTerrain());
if (set == null || set.isEmpty()) {
return null;
}
TravelPoint nearest = null;
double dist = Double.MAX_VALUE;
for (TravelPoint tp : set) {
if (tp.getLocation().distanceTo(l) < dist) {
nearest = tp;
dist = tp.getLocation().distanceTo(l);
}
}
return nearest;
}
}
public TravelPoint getDestination(Terrain t, String destination) {
synchronized (terrainToPoint) {
Set<TravelPoint> set = terrainToPoint.get(t);
if (set == null)
return null;
for (TravelPoint tp : set) {
if (tp.getName().equals(destination))
return tp;
}
return null;
}
}
public int getTimeRemaining() {
return timeRemaining.intValue();
}
public ShuttleStatus getStatus() {
return status;
}
@Override
public void run() {
try {
while (true) {
// GROUNDED
status = ShuttleStatus.GROUNDED;
Thread.sleep(groundTime);
// LEAVING
status = ShuttleStatus.LEAVING;
updateShuttlePostures(false);
Thread.sleep(landTime);
// AWAY
status = ShuttleStatus.AWAY;
for (int timeElapsed = 0; timeElapsed < airTime / 1000; timeElapsed++) {
Thread.sleep(1000); // Sleep for a second
timeRemaining.decrementAndGet();
}
timeRemaining.set(airTime / 1000); // Reset the timer
// LANDING
status = ShuttleStatus.LANDING;
updateShuttlePostures(true);
Thread.sleep(landTime);
}
} catch (InterruptedException e) {
} catch (Exception e) {
e.printStackTrace();
}
}
private void updateShuttlePostures(boolean landed) {
synchronized (points) {
for (TravelPoint tp : points) {
CreatureObject shuttle = tp.getShuttle();
if (shuttle == null || !shuttle.getTemplate().equals(template)) // This TravelPoint has no associated shuttle
continue; // Continue with the next TravelPoint
shuttle.setPosture(landed ? Posture.UPRIGHT : Posture.PRONE);
}
}
}
public enum ShuttleStatus {
LANDING,
GROUNDED,
LEAVING,
AWAY
}
}
@@ -25,17 +25,19 @@
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package services.galaxy;
package services.galaxy.travel;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import network.packets.Packet;
import network.packets.swg.zone.EnterTicketPurchaseModeMessage;
@@ -59,62 +61,53 @@ import resources.encodables.ProsePackage;
import resources.encodables.StringId;
import resources.objects.SWGObject;
import resources.objects.creature.CreatureObject;
import resources.objects.staticobject.StaticObject;
import resources.objects.tangible.OptionFlag;
import resources.player.Player;
import resources.server_info.Log;
import resources.server_info.RelationalServerData;
import resources.server_info.RelationalServerFactory;
import resources.sui.ISuiCallback;
import resources.sui.SuiButtons;
import resources.sui.SuiEvent;
import resources.sui.SuiListBox;
import resources.sui.SuiListBox.SuiListBoxItem;
import resources.sui.SuiMessageBox;
import services.galaxy.travel.TravelGroup;
import services.galaxy.travel.TravelGroup.ShuttleStatus;
import services.objects.ObjectManager;
import utilities.ThreadUtilities;
public class TravelService extends Service {
private static final String DB_TABLE_NAME = "travel";
private static final byte PLANET_NAMES_COLUMN_INDEX = 0;
private static final short TICKET_USE_RADIUS = 25; // The distance a player needs to be within in order to use their ticket
private static final short TICKET_USE_RADIUS = 8; // The distance a player needs to be within in order to use their ticket
private final ObjectManager objectManager;
private Terrain[] travelPlanets;
private final Map<Terrain, Map<Terrain, Integer>> allowedRoutes; // Describes which planets are linked and base prices.
private final DatatableData travelFeeTable;
/**
* This variable stores all the loaded TravelPoints for a given planet.
* All TravelPoints on tatooine are mapped to {@code Terrain.TATOOINE}
*/
private final Map<Terrain, Collection<TravelPoint>> pointsOnPlanet;
private final AtomicInteger groundTime;
private final AtomicInteger airTime;
private final double ticketPriceFactor;
// Fields relating to shuttle take-off and landing
private Posture currentShuttlePosture;
private final Map<String, TravelGroup> travel;
private ExecutorService executor;
private final int timeUntilLand;
private int timeRemaining;
private final long landDelay;
private boolean shuttleLanded;
private final long timeGrounded;
public TravelService(ObjectManager objectManager) {
this.objectManager = objectManager;
allowedRoutes = new HashMap<>();
travelFeeTable = (DatatableData) ClientFactory.getInfoFromFile("datatables/travel/travel.iff");
pointsOnPlanet = new HashMap<>();
travel = new HashMap<>();
ticketPriceFactor = getConfig(ConfigFile.FEATURES).getDouble("TICKET-PRICE-FACTOR", 1);
groundTime = new AtomicInteger(getConfig(ConfigFile.FEATURES).getInt("SHUTTLE-GROUND-TIME", 120));
airTime = new AtomicInteger(getConfig(ConfigFile.FEATURES).getInt("SHUTTLE-AIR-TIME", 60));
timeUntilLand = getConfig(ConfigFile.FEATURES).getInt("SHUTTLE-AWAY-TIME", 60);
timeRemaining = timeUntilLand;
shuttleLanded = true; // Shuttles start off being grounded
currentShuttlePosture = Posture.UPRIGHT;
landDelay = 17000;
timeGrounded = 120000;
createGalaxyTravel("object/creature/npc/theme_park/shared_player_shuttle.iff", 17000);
createGalaxyTravel("object/creature/npc/theme_park/shared_player_transport.iff", 21000);
createGalaxyTravel("object/creature/npc/theme_park/shared_player_transport_theed_hangar.iff", 24000);
loadTravelPlanetNames();
loadAllowedRoutesAndPrices();
loadTravelPoints();
@@ -126,23 +119,18 @@ public class TravelService extends Service {
registerForIntent(ObjectCreatedIntent.TYPE);
}
@Override
public boolean initialize() {
executor = Executors.newSingleThreadExecutor();
return super.initialize();
}
@Override
public boolean start() {
executor.execute(new ShuttleBehaviour());
executor = Executors.newFixedThreadPool(travel.size(), ThreadUtilities.newThreadFactory("travel-shuttles-%d"));
for (TravelGroup gt : travel.values())
executor.execute(gt);
return super.start();
}
@Override
public boolean stop() {
executor.shutdown();
executor.shutdownNow();
return super.stop();
}
@@ -150,14 +138,33 @@ public class TravelService extends Service {
@Override
public void onIntentReceived(Intent i) {
switch(i.getType()) {
case TravelPointSelectionIntent.TYPE: handlePointSelection((TravelPointSelectionIntent) i); break;
case GalacticPacketIntent.TYPE: handleTravelPointRequest((GalacticPacketIntent) i); break;
case TicketPurchaseIntent.TYPE: handleTicketPurchase((TicketPurchaseIntent) i); break;
case TicketUseIntent.TYPE: handleTicketUse((TicketUseIntent) i); break;
case ObjectCreatedIntent.TYPE: handleObjectCreation((ObjectCreatedIntent) i); break;
case TravelPointSelectionIntent.TYPE:
if (i instanceof TravelPointSelectionIntent)
handlePointSelection((TravelPointSelectionIntent) i);
break;
case GalacticPacketIntent.TYPE:
if (i instanceof GalacticPacketIntent)
handleTravelPointRequest((GalacticPacketIntent) i);
break;
case TicketPurchaseIntent.TYPE:
if (i instanceof TicketPurchaseIntent)
handleTicketPurchase((TicketPurchaseIntent) i);
break;
case TicketUseIntent.TYPE:
if (i instanceof TicketUseIntent)
handleTicketUse((TicketUseIntent) i);
break;
case ObjectCreatedIntent.TYPE:
if (i instanceof ObjectCreatedIntent)
handleObjectCreation((ObjectCreatedIntent) i);
break;
}
}
private void createGalaxyTravel(String template, long landTime) {
travel.put(template, new TravelGroup(template, landTime, groundTime.get() * 1000L, airTime.get() * 1000L));
}
private void loadTravelPlanetNames() {
travelPlanets = new Terrain[travelFeeTable.getRowCount()];
@@ -200,34 +207,18 @@ public class TravelService extends Service {
/**
* Travel points are loaded from /serverdata/static/travel.sdb
* A travel point represents a travel destination.
* @author Mads
* @return true if all points were loaded succesfully and false if not.
*/
private boolean loadTravelPoints() {
boolean success = true;
for(Terrain travelPlanet : allowedRoutes.keySet()) {
for (Terrain travelPlanet : allowedRoutes.keySet()) {
String planetName = travelPlanet.getName();
try(RelationalServerData data = RelationalServerFactory.getServerData("static/travel.db", DB_TABLE_NAME)) {
try(ResultSet set = data.selectFromTable(DB_TABLE_NAME, null, "planet = ?", planetName)) {
while(set.next()) {
String pointName = set.getString("name");
double x = set.getDouble("x");
double y = set.getDouble("y");
double z = set.getDouble("z");
String type = set.getString("type");
TravelPoint point = new TravelPoint(pointName, new Location(x, y, z, travelPlanet), type.equals("starport"), true);
Collection<TravelPoint> pointsOnCurrentPlanet = pointsOnPlanet.get(travelPlanet);
if(pointsOnCurrentPlanet == null) {
pointsOnCurrentPlanet = new ArrayList<>();
pointsOnPlanet.put(travelPlanet, pointsOnCurrentPlanet);
}
pointsOnCurrentPlanet.add(point);
try (RelationalServerData data = RelationalServerFactory.getServerData("static/travel.db", DB_TABLE_NAME)) {
try (ResultSet set = data.selectFromTable(DB_TABLE_NAME, null, "planet = ?", planetName)) {
while (set.next()) {
loadTravelPoint(set, travelPlanet);
}
} catch (SQLException e) {
Log.e("TravelService", String.format("Failed to load a travel point for %s. %s", planetName, e.getLocalizedMessage()));
@@ -240,9 +231,30 @@ public class TravelService extends Service {
return success;
}
private void loadTravelPoint(ResultSet set, Terrain travelPlanet) throws SQLException {
String pointName = set.getString("name");
double x = set.getDouble("x");
double y = set.getDouble("y");
double z = set.getDouble("z");
String type = set.getString("type");
TravelPoint point = new TravelPoint(pointName, new Location(x, y, z, travelPlanet), type.equals("starport"), true);
switch (type) {
case "shuttleport":
travel.get("object/creature/npc/theme_park/shared_player_shuttle.iff").addTravelPoint(point);
break;
case "starport":
travel.get("object/creature/npc/theme_park/shared_player_transport.iff").addTravelPoint(point);
break;
case "theed_starport":
travel.get("object/creature/npc/theme_park/shared_player_transport_theed_hangar.iff").addTravelPoint(point);
break;
}
}
private Collection<Integer> getAdditionalCosts(Location objectLocation, Collection<TravelPoint> points) {
Collection<Integer> additionalCosts = new ArrayList<>();
TravelPoint nearest = nearestTravelPoint(objectLocation);
TravelPoint nearest = getNearestTravelPoint(objectLocation);
for(TravelPoint point : points) {
additionalCosts.add(getAdditionalCost(nearest.getLocation(), point.getLocation()));
@@ -278,43 +290,31 @@ public class TravelService extends Service {
return additionalCost;
}
private Collection<TravelPoint> getPointsForPlanet(Location location, String planetName) {
Collection<TravelPoint> points = new ArrayList<>();
Terrain objectTerrain = location.getTerrain();
Terrain destinationTerrain = Terrain.getTerrainFromName(planetName);
Collection<TravelPoint> candidatePoints = pointsOnPlanet.get(destinationTerrain);
for(TravelPoint candidatePoint : candidatePoints) {
if(objectTerrain == destinationTerrain) {
// If the destination planet is the same as our current
points.addAll(candidatePoints);
break; // Then return all the points on this planet
} else if(candidatePoint.isStarport()) { // If the terrains aren't the same, we only want to add the starports.
points.add(candidatePoint);
}
}
return points;
}
private void handlePointSelection(TravelPointSelectionIntent tpsi) {
CreatureObject traveler = tpsi.getCreature();
traveler.sendSelf(new EnterTicketPurchaseModeMessage(traveler.getTerrain().getName(), nearestTravelPoint(traveler.getWorldLocation()).getName(), tpsi.isInstant()));
traveler.sendSelf(new EnterTicketPurchaseModeMessage(traveler.getTerrain().getName(), getNearestTravelPoint(traveler.getWorldLocation()).getName(), tpsi.isInstant()));
}
private void handleTravelPointRequest(GalacticPacketIntent i) {
Packet p = i.getPacket();
if(p instanceof PlanetTravelPointListRequest ) {
if (p instanceof PlanetTravelPointListRequest) {
PlanetTravelPointListRequest req = (PlanetTravelPointListRequest) p;
String planetName = req.getPlanetName();
Player player = i.getPlayerManager().getPlayerFromNetworkId(i.getNetworkId());
Location objectLocation = player.getCreatureObject().getWorldLocation();
Collection<TravelPoint> pointsForPlanet = getPointsForPlanet(objectLocation, planetName);
TravelPoint nearest = getNearestTravelPoint(objectLocation);
List<TravelPoint> pointsForPlanet = new ArrayList<>();
Terrain to = Terrain.getTerrainFromName(req.getPlanetName());
if (to == null) {
Log.e(this, "Unknown terrain in PlanetTravelPointListRequest: %s", req.getPlanetName());
return;
}
for (TravelGroup gt : travel.values())
gt.getPointsForTerrain(pointsForPlanet, nearest, to);
Collections.sort(pointsForPlanet);
player.sendPacket(new PlanetTravelPointListResponse(planetName, pointsForPlanet, getAdditionalCosts(objectLocation, pointsForPlanet)));
player.sendPacket(new PlanetTravelPointListResponse(req.getPlanetName(), pointsForPlanet, getAdditionalCosts(objectLocation, pointsForPlanet)));
}
}
@@ -345,13 +345,15 @@ public class TravelService extends Service {
private void handleTicketPurchase(TicketPurchaseIntent i) {
CreatureObject purchaser = i.getPurchaser();
Location purchaserWorldLocation = purchaser.getWorldLocation();
TravelPoint nearestPoint = nearestTravelPoint(purchaserWorldLocation);
TravelPoint nearestPoint = getNearestTravelPoint(purchaserWorldLocation);
TravelPoint destinationPoint = getDestinationPoint(Terrain.getTerrainFromName(i.getDestinationPlanet()), i.getDestinationName());
Player purchaserOwner = purchaser.getOwner();
boolean roundTrip = i.isRoundTrip();
if(nearestPoint == null || destinationPoint == null)
if (nearestPoint == null || destinationPoint == null) {
Log.w(this, "Unable to purchase ticket! Nearest Point: %s Destination Point: %s", nearestPoint, destinationPoint);
return;
}
int ticketPrice = getTotalTicketPrice(nearestPoint, destinationPoint, roundTrip);
int newBankBalance = purchaser.getBankBalance();
@@ -418,26 +420,37 @@ public class TravelService extends Service {
ticket.addAttribute("@obj_attr_n:travel_arrival_planet", "@planet_n:" + destination.getLocation().getTerrain().getName());
ticket.addAttribute("@obj_attr_n:travel_arrival_point", destination.getName());
receiver.getSlottedObject("inventory").addObject(ticket);
ticket.moveToContainer(receiver.getSlottedObject("inventory"));
}
private void handleTicketUse(TicketUseIntent i) {
if(isShuttleAvailable()) {
// The shuttle is available at this time
if(i.getTicket() == null)
handleTicketUseSui(i);
else
handleTicketUseClick(i);
} else { // The shuttle isn't available
if(isShuttleBoarding()) { // Unavailable but about to board
TravelPoint point = getNearestTravelPoint(i.getPlayer().getCreatureObject().getWorldLocation());
TravelGroup travel = null;
if (point.getShuttle() == null) {
Log.w(this, "No travel point shuttle near player: %s", i.getPlayer().getCreatureObject().getWorldLocation());
return;
}
travel = this.travel.get(point.getShuttle().getTemplate());
if (travel == null) {
Log.e(this, "Travel point is null for shuttle: " + point.getShuttle());
return;
}
switch (travel.getStatus()) {
case GROUNDED:
if (i.getTicket() == null)
handleTicketUseSui(i);
else
handleTicketUseClick(i);
break;
case LANDING:
new ChatBroadcastIntent(i.getPlayer(), "@travel/travel:shuttle_begin_boarding").broadcast();
} else { // Unavailable but not about to board, because...
if(isShuttleDeparting()) // ... it's departing
new ChatBroadcastIntent(i.getPlayer(), "@travel:shuttle_not_available").broadcast();
else // ... or it's done departing and is completely away
new ChatBroadcastIntent(i.getPlayer(), new ProsePackage(new StringId("travel/travel", "shuttle_board_delay"), "DI", timeRemaining)).broadcast();
}
break;
case LEAVING:
new ChatBroadcastIntent(i.getPlayer(), "@travel:shuttle_not_available").broadcast();
break;
case AWAY:
new ChatBroadcastIntent(i.getPlayer(), new ProsePackage(new StringId("travel/travel", "shuttle_board_delay"), "DI", travel.getTimeRemaining())).broadcast();
break;
}
}
@@ -445,68 +458,85 @@ public class TravelService extends Service {
Player player = i.getPlayer();
CreatureObject creature = player.getCreatureObject();
Collection<SWGObject> tickets = creature.getItemsByTemplate("inventory", "object/tangible/travel/travel_ticket/base/shared_base_travel_ticket.iff");
SuiListBox destinationSelection;
List<SWGObject> usableTickets = new ArrayList<>();
for(SWGObject ticket : tickets)
if(isTicket(ticket) && isTicketUsable(ticket))
for (SWGObject ticket : tickets) {
if (isTicket(ticket) && isTicketUsable(ticket))
usableTickets.add(ticket);
}
if(usableTickets.isEmpty()) // They don't have a valid ticket.
if (usableTickets.isEmpty()) // They don't have a valid ticket.
new ChatBroadcastIntent(player, "@travel:no_ticket_for_shuttle").broadcast();
else {
destinationSelection = new SuiListBox(SuiButtons.OK_CANCEL, "@travel:select_destination", "@travel:select_destination");
SuiListBox ticketBox = new SuiListBox(SuiButtons.OK_CANCEL, "@travel:select_destination", "@travel:select_destination");
for(SWGObject usableTicket : usableTickets) {
TravelPoint destinationPoint = getDestinationPoint(usableTicket);
destinationSelection.addListItem(destinationPoint.getSuiFormat(), destinationPoint);
ticketBox.addListItem(destinationPoint.getSuiFormat(), destinationPoint);
}
destinationSelection.addOkButtonCallback("handleSelectedItem", new DestinationSelectionSuiCallback(destinationSelection, usableTickets));
destinationSelection.display(player);
ticketBox.addOkButtonCallback("handleSelectedItem", (callbackPlayer, actor, event, parameters) -> {
handleTicketUse(callbackPlayer, usableTickets.get(SuiListBox.getSelectedRow(parameters)));
});
ticketBox.display(player);
}
}
private void handleTicketUseClick(TicketUseIntent i) {
CreatureObject traveler = i.getPlayer().getCreatureObject();
handleTicketUse(i.getPlayer(), i.getTicket());
}
private void handleTicketUse(Player player, SWGObject ticket) {
CreatureObject traveler = player.getCreatureObject();
Location worldLoc = traveler.getWorldLocation();
TravelPoint nearestPoint = nearestTravelPoint(worldLoc);
double distanceToNearestPoint = worldLoc.distanceTo(nearestPoint.getShuttle().getLocation());
SWGObject ticket = i.getTicket();
Player player = i.getPlayer();
if(isTicket(ticket)) {
if(isTicketUsable(ticket)) {
if(distanceToNearestPoint <= TICKET_USE_RADIUS) {
// They can use their ticket if they're within range.
teleportAndDestroyTicket(getDestinationPoint(ticket), ticket, traveler);
} else {
// They're out of range - let them know.
new ChatBroadcastIntent(player, "@travel:boarding_too_far").broadcast();
}
} else {
// This ticket isn't valid for this point
new ChatBroadcastIntent(player, "@travel:wrong_shuttle").broadcast();
}
TravelPoint nearestPoint = getNearestTravelPoint(worldLoc);
double distanceToNearestPoint = worldLoc.distanceTo(nearestPoint.getCollector().getWorldLocation());
if (!isTicket(ticket)) {
Log.e(this, "%s attempted to use an object that isn't a ticket!", player);
} else if (nearestPoint.getGroup().getStatus() != ShuttleStatus.GROUNDED) {
int time = nearestPoint.getGroup().getTimeRemaining();
new ChatBroadcastIntent(player, new ProsePackage(new StringId("travel/travel", "shuttle_board_delay"), "DI", time)).broadcast();
} else if (!isTicketUsable(ticket)) {
// This ticket isn't valid for this point
new ChatBroadcastIntent(player, "@travel:wrong_shuttle").broadcast();
} else if (distanceToNearestPoint <= TICKET_USE_RADIUS) {
// They can use their ticket if they're within range.
Log.i(this, "%s/%s is traveling from %s to %s", player.getUsername(), traveler.getName(), nearestPoint.getName(), getDestinationPoint(ticket).getName());
teleportAndDestroyTicket(getDestinationPoint(ticket), ticket, traveler);
} else {
new ChatBroadcastIntent(player, "@travel:boarding_too_far").broadcast();
}
}
private void handleObjectCreation(ObjectCreatedIntent i) {
SWGObject object = i.getObject();
String template = object.getTemplate();
// There are non-functional shuttles, which are StaticObject. We run an instanceof check to make sure that we ignore those.
if((template.contains("shared_player_shuttle") || template.contains("shared_player_transport")) && object instanceof CreatureObject) {
Location shuttleLocation = object.getLocation();
TravelPoint pointForShuttle = nearestTravelPoint(shuttleLocation);
if (travel.containsKey(object.getTemplate()) && !(object instanceof StaticObject)) {
Location shuttleLocation = object.getWorldLocation();
TravelPoint pointForShuttle = getNearestTravelPoint(shuttleLocation);
CreatureObject shuttle = (CreatureObject) object;
if (pointForShuttle == null) {
Log.w(this, "No point for shuttle at location: " + object.getWorldLocation());
return;
}
// Assign the shuttle to the nearest travel point
pointForShuttle.setShuttle(shuttle);
shuttle.setOptionFlags(OptionFlag.INVULNERABLE);
shuttle.setPosture(Posture.UPRIGHT);
shuttle.setShownOnRadar(false);
} else if (object.getTemplate().equals("object/tangible/travel/ticket_collector/shared_ticket_collector.iff")) {
TravelPoint pointForCollector = getNearestTravelPoint(object.getWorldLocation());
if (pointForCollector == null) {
Log.w(this, "No point for collector at location: " + object.getWorldLocation());
return;
}
pointForCollector.setCollector(object);
}
}
@@ -526,9 +556,8 @@ public class TravelService extends Service {
}
private boolean isTicketUsable(SWGObject ticket) {
CreatureObject ticketOwner = ticket.getOwner().getCreatureObject();
Location worldLoc = ticketOwner.getWorldLocation();
TravelPoint nearest = nearestTravelPoint(worldLoc);
Location worldLoc = ticket.getOwner().getCreatureObject().getWorldLocation();
TravelPoint nearest = getNearestTravelPoint(worldLoc);
String departurePoint = ticket.getAttribute("@obj_attr_n:travel_departure_point");
String departurePlanet = ticket.getAttribute("@obj_attr_n:travel_departure_planet");
Terrain departureTerrain = Terrain.getTerrainFromName(departurePlanet.split(":")[1]);
@@ -542,123 +571,28 @@ public class TravelService extends Service {
}
private TravelPoint getDestinationPoint(Terrain terrain, String pointName) {
TravelPoint currentResult = null;
for(TravelPoint candidate : pointsOnPlanet.get(terrain)) {
if(candidate.getName().equals(pointName)) {
currentResult = candidate;
break;
for (TravelGroup gt : travel.values()) {
TravelPoint point = gt.getDestination(terrain, pointName);
if (point != null)
return point;
}
return null;
}
private TravelPoint getNearestTravelPoint(Location objectLocation) {
TravelPoint nearest = null;
double dist = Double.MAX_VALUE;
for (TravelGroup gt : travel.values()) {
TravelPoint point = gt.getNearestPoint(objectLocation);
if (point == null)
continue;
double d = point.getLocation().distanceTo(objectLocation);
if (d < dist) {
nearest = point;
dist = d;
}
}
return currentResult;
return nearest;
}
private TravelPoint nearestTravelPoint(Location objectLocation) {
TravelPoint currentResult = null;
double currentResultDistance = Double.MAX_VALUE;
double candidateDistance;
Collection<TravelPoint> pointsForPlanet = pointsOnPlanet.get(objectLocation.getTerrain());
if(pointsForPlanet == null)
return null;
for(TravelPoint candidate : pointsForPlanet) {
if(currentResult == null) { // Will occur upon the first iteration.
currentResult = candidate; // The first candidate will always be the first possible result.
currentResultDistance = getDistanceFromPoint(currentResult, objectLocation);
} else {
candidateDistance = getDistanceFromPoint(candidate, objectLocation);
if(candidateDistance < currentResultDistance) {
currentResult = candidate;
currentResultDistance = candidateDistance;
}
}
}
return currentResult;
}
private double getDistanceFromPoint(TravelPoint point, Location objectLocation) {
return point.getLocation().distanceTo(objectLocation);
}
private void updateShuttlePostures(Posture posture) {
for(Collection<TravelPoint> travelPoints : pointsOnPlanet.values()) {
for(TravelPoint tp : travelPoints) {
CreatureObject shuttle = tp.getShuttle();
if(shuttle == null) // This TravelPoint has no associated shuttle
continue; // Continue with the next TravelPoint
shuttle.setPosture(posture);
}
}
currentShuttlePosture = posture;
}
private boolean isShuttleAvailable() {
return currentShuttlePosture == Posture.UPRIGHT && shuttleLanded;
}
private boolean isShuttleBoarding() {
return currentShuttlePosture == Posture.UPRIGHT && !shuttleLanded;
}
private boolean isShuttleDeparting() {
return currentShuttlePosture == Posture.PRONE && !shuttleLanded && timeRemaining == timeUntilLand;
}
private class DestinationSelectionSuiCallback implements ISuiCallback {
private final SuiListBox destinationSelection;
private final List<SWGObject> usableTickets;
private DestinationSelectionSuiCallback(SuiListBox destinationSelection, List<SWGObject> usableTickets) {
this.destinationSelection = destinationSelection;
this.usableTickets = usableTickets;
}
@Override
public void handleEvent(Player player, SWGObject actor, SuiEvent event, Map<String, String> parameters) {
int selection = SuiListBox.getSelectedRow(parameters);
SuiListBoxItem selectedItem = destinationSelection.getListItem(selection);
TravelPoint selectedDestination = (TravelPoint) selectedItem.getObject();
teleportAndDestroyTicket(selectedDestination, usableTickets.get(selection), player.getCreatureObject());
}
}
private class ShuttleBehaviour implements Runnable {
@Override
public void run() {
while(true) {
try {
// GROUNDED
Thread.sleep(timeGrounded);
// LEAVE
updateShuttlePostures(Posture.PRONE);
shuttleLanded = false;
Thread.sleep(landDelay);
// Make the shuttle stay away for some time.
for(long timeElapsed = 0; timeUntilLand > timeElapsed; timeRemaining--, timeElapsed++) {
Thread.sleep(1000); // Sleep for a second
}
timeRemaining = timeUntilLand; // Reset the timer
// LANDING
updateShuttlePostures(Posture.UPRIGHT);
Thread.sleep(landDelay);
shuttleLanded = true;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
+32 -30
View File
@@ -31,9 +31,7 @@ import intents.GroupEventIntent;
import intents.NotifyPlayersPacketIntent;
import intents.PlayerEventIntent;
import intents.chat.ChatRoomUpdateIntent;
import intents.object.ObjectCreateIntent;
import intents.object.ObjectIdRequestIntent;
import intents.object.ObjectIdResponseIntent;
import intents.object.ObjectCreatedIntent;
import network.packets.swg.zone.chat.ChatSystemMessage;
import resources.chat.ChatAvatar;
import resources.control.Intent;
@@ -44,7 +42,6 @@ import resources.encodables.StringId;
import resources.objects.creature.CreatureObject;
import resources.objects.group.GroupObject;
import resources.player.Player;
import resources.player.PlayerEvent;
import resources.server_info.Log;
import services.objects.ObjectCreator;
import services.player.PlayerManager;
@@ -59,19 +56,16 @@ import java.util.Map;
* Created by Waverunner on 10/4/2015
*/
public class GroupService extends Service {
private final List<Long> reservedIds = new ArrayList<>();
private final Map<Long, GroupObject> groups = new HashMap<>();
public GroupService() {
registerForIntent(GroupEventIntent.TYPE);
registerForIntent(PlayerEventIntent.TYPE);
registerForIntent(ObjectIdResponseIntent.TYPE);
}
@Override
public boolean start() {
new ObjectIdRequestIntent("GroupService", 50).broadcast();
return super.start();
}
@@ -83,18 +77,9 @@ public class GroupService extends Service {
if (i instanceof GroupEventIntent)
handleGroupEventIntent((GroupEventIntent) i);
break;
case ObjectIdResponseIntent.TYPE:
if (!(i instanceof ObjectIdResponseIntent) || !((ObjectIdResponseIntent) i).getIdentifier().equals("GroupService"))
break;
reservedIds.addAll(((ObjectIdResponseIntent)i).getReservedIds());
break;
case PlayerEventIntent.TYPE:
if (i instanceof PlayerEventIntent) {
PlayerEventIntent pei = (PlayerEventIntent) i;
if (pei.getEvent() == PlayerEvent.PE_FIRST_ZONE) {
pei.getPlayer().getCreatureObject().setGroupId(0);
}
}
if (i instanceof PlayerEventIntent)
handlePlayerEventIntent((PlayerEventIntent) i);
break;
default: break;
}
@@ -114,6 +99,32 @@ public class GroupService extends Service {
}
}
private void handlePlayerEventIntent(PlayerEventIntent intent) {
switch(intent.getEvent()) {
case PE_FIRST_ZONE:
handleMemberRezoned(intent.getPlayer());
break;
default: break;
}
}
private void handleMemberRezoned(Player player) {
CreatureObject creatureObject = player.getCreatureObject();
long groupId = creatureObject.getGroupId();
if (groupId == 0)
return;
GroupObject groupObject = getGroup(creatureObject.getGroupId());
if (groupObject == null) {
// Group was destroyed while logged out
creatureObject.setGroupId(0);
return;
}
groupObject.updateMember(creatureObject);
}
private void handleGroupDisband(Player player, CreatureObject target) {
CreatureObject creo = player.getCreatureObject();
@@ -268,7 +279,7 @@ public class GroupService extends Service {
}
private GroupObject createGroup(Player player) {
GroupObject group = (GroupObject) ObjectCreator.createObjectFromTemplate(getNextObjectId(), "object/group/shared_group_object.iff");
GroupObject group = (GroupObject) ObjectCreator.createObjectFromTemplate("object/group/shared_group_object.iff");
if (group == null)
return null;
@@ -276,7 +287,7 @@ public class GroupService extends Service {
groups.put(group.getObjectId(), group);
new ObjectCreateIntent(group).broadcast();
new ObjectCreatedIntent(group).broadcast();
String galaxy = player.getGalaxyName();
new ChatRoomUpdateIntent(getGroupChatPath(group.getObjectId(), galaxy), String.valueOf(group.getObjectId()), null,
@@ -285,15 +296,6 @@ public class GroupService extends Service {
return group;
}
private long getNextObjectId() {
synchronized (reservedIds) {
if (reservedIds.size() <= 5)
new ObjectIdRequestIntent("GroupService", 50).broadcast();
return reservedIds.remove(0);
}
}
private void sendGroupSystemMessage(GroupObject group, String id) {
Map<String, Long> members = group.getGroupMembers();
+124 -239
View File
@@ -28,327 +28,212 @@
package services.network;
import intents.network.CloseConnectionIntent;
import intents.network.InboundPacketIntent;
import intents.network.ConnectionClosedIntent;
import intents.network.OutboundPacketIntent;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import network.NetworkClient;
import network.PacketReceiver;
import network.PacketSender;
import network.packets.Packet;
import network.packets.soe.Disconnect;
import network.packets.soe.SessionRequest;
import network.packets.soe.SessionResponse;
import network.packets.soe.Disconnect.DisconnectReason;
import resources.config.ConfigFile;
import resources.control.Intent;
import resources.control.Manager;
import resources.network.ServerType;
import resources.network.UDPServer.UDPPacket;
import resources.network.DisconnectReason;
import resources.network.TCPServer;
import resources.network.TCPServer.TCPCallback;
import resources.server_info.Log;
import utilities.ThreadUtilities;
public class NetworkClientManager extends Manager implements PacketReceiver {
public class NetworkClientManager extends Manager implements TCPCallback, PacketSender {
private final Map <InetAddress, List <NetworkClient>> clients;
private final Map <Long, NetworkClient> networkClients;
private final Queue<ReceivedPacket> receivedPackets;
private final ScheduledExecutorService packetResender;
private final ExecutorService packetProcessor;
private final Random crcGenerator;
private final PacketSender packetSender;
private final Runnable processPacketRunnable;
private final Runnable packetResendRunnable;
private long networkId;
private final Map <InetSocketAddress, Long> sockets;
private final Map <Long, NetworkClient> clients;
private final Queue<NetworkClient> processQueue;
private final ExecutorService clientProcessor;
private final Runnable processBufferRunnable;
private final AtomicLong networkIdCounter;
private final TCPServer tcpServer;
public NetworkClientManager(PacketSender packetSender) {
this.packetSender = packetSender;
clients = new HashMap<InetAddress, List<NetworkClient>>();
networkClients = new HashMap<Long, NetworkClient>();
receivedPackets = new LinkedList<>();
packetResender = Executors.newSingleThreadScheduledExecutor(ThreadUtilities.newThreadFactory("packet-resender"));
packetProcessor = Executors.newCachedThreadPool(ThreadUtilities.newThreadFactory("packet-processor-%d"));
crcGenerator = new Random();
processPacketRunnable = new Runnable() {
public NetworkClientManager() {
sockets = new HashMap<InetSocketAddress, Long>();
clients = new Hashtable<Long, NetworkClient>();
processQueue = new LinkedList<>();
networkIdCounter = new AtomicLong(1);
clientProcessor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), ThreadUtilities.newThreadFactory("packet-processor-%d"));
processBufferRunnable = new Runnable() {
public void run() {
synchronized (receivedPackets) {
ReceivedPacket recv = receivedPackets.poll();
if (recv == null)
return;
handlePacket(recv.getType(), recv.getPacket());
try {
NetworkClient client;
synchronized (processQueue) {
client = processQueue.poll();
if (client == null)
return;
}
client.process();
} catch (Exception e) {
e.printStackTrace();
}
}
};
packetResendRunnable = new Runnable() {
public void run() {
resendOldUnacknowledged();
}
};
networkId = 0;
tcpServer = new TCPServer(getBindPort(), getBufferSize());
registerForIntent(InboundPacketIntent.TYPE);
registerForIntent(OutboundPacketIntent.TYPE);
registerForIntent(CloseConnectionIntent.TYPE);
}
@Override
public boolean initialize() {
packetResender.scheduleAtFixedRate(packetResendRunnable, 0, 200, TimeUnit.MILLISECONDS);
return super.initialize();
public boolean start() {
try {
tcpServer.bind();
tcpServer.setCallback(this);
} catch (IOException e) {
e.printStackTrace();
return false;
}
return super.start();
}
@Override
public boolean stop() {
for (NetworkClient client : networkClients.values()) {
client.sendPacket(new Disconnect(client.getConnectionId(), DisconnectReason.APPLICATION));
}
tcpServer.close();
return super.stop();
}
@Override
public boolean terminate() {
packetProcessor.shutdownNow();
packetResender.shutdownNow();
clientProcessor.shutdownNow();
boolean success = true;
try {
success = packetProcessor.awaitTermination(5, TimeUnit.SECONDS);
success = packetResender.awaitTermination(5, TimeUnit.SECONDS) && success;
success = clientProcessor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
return super.terminate() && success;
}
@Override
public void receivePacket(ServerType type, UDPPacket packet) {
synchronized (receivedPackets) {
receivedPackets.add(new ReceivedPacket(type, packet));
}
packetProcessor.submit(processPacketRunnable);
}
@Override
public void onIntentReceived(Intent i) {
if (i instanceof OutboundPacketIntent) {
Packet p = ((OutboundPacketIntent)i).getPacket();
if (p != null)
handleOutboundPacket(((OutboundPacketIntent) i).getNetworkId(), p);
} else if (i instanceof InboundPacketIntent) {
Packet p = ((InboundPacketIntent) i).getPacket();
if (p != null) {
if (p instanceof SessionRequest)
initializeSession((SessionRequest) p);
if (p instanceof Disconnect)
disconnectSession(((InboundPacketIntent) i).getNetworkId(), (Disconnect) p);
}
} else if (i instanceof CloseConnectionIntent) {
int connId = ((CloseConnectionIntent)i).getConnectionId();
long netId = ((CloseConnectionIntent)i).getNetworkId();
DisconnectReason reason = ((CloseConnectionIntent)i).getReason();
removeClient(netId);
sendPacket(netId, new Disconnect(connId, reason));
deleteSession(netId);
}
}
private void initializeSession(SessionRequest req) {
NetworkClient client = getClient(req.getAddress(), req.getPort());
if (client == null) {
return;
}
SessionResponse outPacket = new SessionResponse();
outPacket.setConnectionID(client.getConnectionId());
outPacket.setCrcSeed(client.getCrc());
outPacket.setCrcLength(2);
outPacket.setEncryptionFlag((short) 1);
outPacket.setXorLength((byte) 4);
outPacket.setUdpSize(getConfig(ConfigFile.NETWORK).getInt("MAX-PACKET-SIZE", 496));
sendPacket(client.getNetworkId(), outPacket);
@Override
public void onIncomingConnection(Socket s) {
SocketAddress addr = s.getRemoteSocketAddress();
if (addr instanceof InetSocketAddress)
createSession(networkIdCounter.incrementAndGet(), (InetSocketAddress) addr);
else if (addr != null)
Log.e(this, "Incoming connection has socket address of instance: %s", addr.getClass().getSimpleName());
}
private void disconnectSession(long networkId, Disconnect d) {
disconnectSession(networkId, d.getAddress(), d.getPort(), d.getReason());
@Override
public void onConnectionDisconnect(Socket s) {
SocketAddress addr = s.getRemoteSocketAddress();
if (addr instanceof InetSocketAddress)
onSessionDisconnect((InetSocketAddress) addr);
else if (addr != null)
Log.e(this, "Connection Disconnected. Has socket address of instance: %s", addr.getClass().getSimpleName());
}
private void disconnectSession(long networkId, InetAddress addr, int port, DisconnectReason reason) {
removeClient(networkId, addr, port);
@Override
public void onIncomingData(Socket s, byte [] data) {
SocketAddress addr = s.getRemoteSocketAddress();
if (addr instanceof InetSocketAddress)
handleIncomingData((InetSocketAddress) addr, data);
else if (addr != null)
Log.e(this, "Incoming data has socket address of instance: %s", addr.getClass().getSimpleName());
}
private int generateCrc() {
int crc = 0;
do {
crc = crcGenerator.nextInt();
} while (crc == 0);
return crc;
@Override
public void sendPacket(InetSocketAddress sock, byte[] data) {
tcpServer.send(sock, data);
}
private void resendOldUnacknowledged() {
private int getBindPort() {
return getConfig(ConfigFile.NETWORK).getInt("BIND-PORT", 44463);
}
private int getBufferSize() {
return getConfig(ConfigFile.NETWORK).getInt("BUFFER-SIZE", 4096);
}
private void createSession(long networkId, InetSocketAddress address) {
NetworkClient client = new NetworkClient(address, networkId, this);
synchronized (clients) {
for (NetworkClient client : networkClients.values()) {
client.resendOldUnacknowledged();
flushPackets();
sockets.put(address, networkId);
clients.put(networkId, client);
}
client.onConnected();
}
private void onSessionDisconnect(InetSocketAddress address) {
synchronized (clients) {
Long networkId = sockets.get(address);
if (networkId != null) {
deleteSession(networkId);
new ConnectionClosedIntent(networkId, DisconnectReason.OTHER_SIDE_TERMINATED).broadcast();
} else {
System.err.println("Network ID not found for " + address + "!");
}
}
}
private void deleteSession(long networkId) {
synchronized (clients) {
NetworkClient client = clients.remove(networkId);
if (client == null) {
System.err.println("No NetworkClient found for network id: " + networkId);
return;
}
sockets.remove(client.getAddress());
}
}
private void handleOutboundPacket(long networkId, Packet p) {
synchronized (clients) {
NetworkClient client = networkClients.get(networkId);
NetworkClient client = clients.get(networkId);
if (client != null)
client.sendPacket(p);
else
Log.w(this, "NetworkClient does not exist for ID: %d", networkId);
}
}
private void handlePacket(ServerType type, UDPPacket p) {
InetAddress addr = p.getAddress();
if (addr == null)
return;
if (p.getData().length == 14 && p.getData()[0] == 0 && p.getData()[1] == 1) {
handleSessionRequest(type, p);
return;
}
if (type == ServerType.LOGIN || type == ServerType.ZONE)
handlePacket(p.getAddress(), p.getPort(), type, p.getData());
}
private void handlePacket(InetAddress addr, int port, ServerType type, byte [] data) {
private void handleIncomingData(InetSocketAddress addr, byte [] data) {
synchronized (clients) {
List <NetworkClient> ipList = clients.get(addr);
if (ipList != null) {
synchronized (ipList) {
for (NetworkClient c : ipList) {
if (c.processPacket(type, data)) {
c.updateNetworkInfo(addr, port);
}
}
}
Long netId = sockets.get(addr);
if (netId == null) {
Log.w(this, "Unknown socket address! Address: %s", addr);
return;
}
}
}
private void handleSessionRequest(ServerType type, UDPPacket p) {
SessionRequest req = new SessionRequest(ByteBuffer.wrap(p.getData()));
req.setAddress(p.getAddress());
req.setPort(p.getPort());
NetworkClient client = createSession(type, req);
if (client != null)
client.processPacket(type, p.getData());
}
private NetworkClient createSession(ServerType type, SessionRequest req) {
NetworkClient client = getClient(req.getAddress(), req.getPort());
if (client != null) {
if (client.getConnectionId() == req.getConnectionID()) {
client.resetNetwork();
client.updateNetworkInfo(req.getAddress(), req.getPort());
return client;
} else
return null;
}
client = createClient(type, req.getAddress(), req.getPort());
client.setCrc(generateCrc());
client.setConnectionId(req.getConnectionID());
return client;
}
private NetworkClient createClient(ServerType type, InetAddress addr, int port) {
synchronized (clients) {
NetworkClient client = new NetworkClient(type, addr, port, networkId++, packetSender);
List <NetworkClient> ipList = clients.get(addr);
if (ipList == null) {
ipList = new ArrayList<NetworkClient>();
clients.put(addr, ipList);
}
synchronized (ipList) {
ipList.add(client);
}
networkClients.put(client.getNetworkId(), client);
return client;
}
}
private NetworkClient getClient(InetAddress addr, int port) {
synchronized (clients) {
List <NetworkClient> ipList = clients.get(addr);
if (ipList != null) {
synchronized (ipList) {
for (NetworkClient c : ipList) {
if (c.getPort() == port)
return c;
}
}
}
}
return null;
}
private boolean removeClient(long networkId) {
synchronized (clients) {
NetworkClient client = networkClients.remove(networkId);
NetworkClient client = clients.get(netId);
if (client != null) {
InetAddress addr = client.getAddress();
int port = client.getPort();
List <NetworkClient> ipList = clients.get(addr);
if (ipList != null) {
synchronized (ipList) {
for (NetworkClient c : ipList) {
if (c.getPort() == port) {
ipList.remove(c);
return true;
}
}
}
client.addToBuffer(data);
synchronized (processQueue) {
processQueue.add(client);
}
client.resetNetwork();
}
}
return false;
}
private boolean removeClient(long networkId, InetAddress addr, int port) {
synchronized (clients) {
networkClients.remove(networkId);
List <NetworkClient> ipList = clients.get(addr);
if (ipList != null) {
synchronized (ipList) {
for (NetworkClient c : ipList) {
if (c.getPort() == port) {
ipList.remove(c);
return true;
}
}
}
}
}
return false;
}
private static class ReceivedPacket {
private final ServerType type;
private final UDPPacket packet;
public ReceivedPacket(ServerType type, UDPPacket packet) {
this.type = type;
this.packet = packet;
}
public ServerType getType() {
return type;
}
public UDPPacket getPacket() {
return packet;
clientProcessor.execute(processBufferRunnable);
} else
Log.w(this, "Unknown connection! Network ID: %d Address: %s", netId, addr);
}
}
@@ -1,199 +0,0 @@
/***********************************************************************************
* Copyright (c) 2015 /// 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 services.network;
import java.net.InetAddress;
import java.net.UnknownHostException;
import network.PacketReceiver;
import network.PacketSender;
import resources.Galaxy;
import resources.config.ConfigFile;
import resources.control.Service;
import resources.network.ServerType;
import resources.network.UDPServer;
import resources.network.UDPServer.UDPCallback;
import resources.network.UDPServer.UDPPacket;
import resources.server_info.Config;
public class NetworkListenerService extends Service implements PacketSender {
private Server login;
private Server zone;
private Server ping;
private Galaxy galaxy;
public NetworkListenerService(Galaxy galaxy) {
this.galaxy = galaxy;
login = new Server(ServerType.LOGIN);
zone = new Server(ServerType.ZONE);
ping = new Server(ServerType.PING);
}
public void setPacketReceiver(PacketReceiver packetReceiver) {
login.setPacketReceiver(packetReceiver);
zone.setPacketReceiver(packetReceiver);
ping.setPacketReceiver(packetReceiver);
}
private InetAddress getBindAddr(Config c, String firstTry, String secondTry) {
String t = firstTry;
try {
if (c.containsKey(firstTry))
return InetAddress.getByName(c.getString(firstTry, "127.0.0.1"));
t = secondTry;
if (c.containsKey(secondTry))
return InetAddress.getByName(c.getString(secondTry, "127.0.0.1"));
} catch (UnknownHostException e) {
System.err.println("NetworkListenerService: Unknown host for IP: " + t);
}
return null;
}
@Override
public boolean initialize() {
Config network = getConfig(ConfigFile.NETWORK);
int packetSize = network.getInt("MAX-PACKET-SIZE", 496);
InetAddress loginBind = getBindAddr(network, "LOGIN-BIND-ADDR", "BIND-ADDR");
InetAddress zoneBind = getBindAddr(network, "ZONE-BIND-ADDR", "BIND-ADDR");
InetAddress pingBind = getBindAddr(network, "PING-BIND-ADDR", "BIND-ADDR");
boolean init = true;
init = login.initialize(loginBind, network.getInt("LOGIN-PORT", 44453), packetSize) && init;
init = zone.initialize(zoneBind, galaxy.getZonePort(), packetSize) && init;
init = ping.initialize(pingBind, galaxy.getPingPort(), packetSize) && init;
return super.initialize() && isOperational() && init;
}
@Override
public boolean start() {
boolean start = super.start();
login.start();
zone.start();
ping.start();
System.out.println("NetworkListenerService: Login/Zone/Ping Servers are now online.");
return start;
}
@Override
public boolean terminate() {
login.terminate();
zone.terminate();
ping.terminate();
return super.terminate();
}
@Override
public boolean isOperational() {
if (!login.isRunning())
return false;
if (!zone.isRunning())
return false;
if (!ping.isRunning())
return false;
return true;
}
@Override
public void sendPacket(ServerType type, UDPPacket packet) {
send(type, packet.getAddress(), packet.getPort(), packet.getData());
}
public void send(ServerType type, InetAddress addr, int port, byte [] data) {
switch (type) {
case LOGIN:
login.send(addr, port, data);
break;
case ZONE:
zone.send(addr, port, data);
break;
case PING: // Nobody gets to send pings
case UNKNOWN:
break;
}
}
private class Server implements UDPCallback {
private final ServerType type;
private PacketReceiver packetReceiver;
private UDPServer server;
public Server(ServerType type) {
this.type = type;
}
public void setPacketReceiver(PacketReceiver packetReceiver) {
this.packetReceiver = packetReceiver;
}
public boolean initialize(InetAddress bindAddr, int port, int maxPacket) {
try {
if (bindAddr == null)
server = new UDPServer(port, maxPacket);
else
server = new UDPServer(bindAddr, port, maxPacket);
} catch (Exception e) {
System.err.println("NetworkListener: Failed to initialize UDP server [" + type + "] on " + bindAddr + ":" + port + ". Reason: " + e.getMessage());
return false;
}
return isRunning();
}
public boolean start() {
if (server == null)
return false;
server.setCallback(this);
return true;
}
public boolean terminate() {
if (server == null)
return false;
server.close();
return true;
}
public boolean isRunning() {
if (server == null)
return false;
return server.isRunning();
}
public void send(InetAddress addr, int port, byte [] data) {
server.send(port, addr, data);
}
public void onReceivedPacket(UDPPacket packet) {
if (type == ServerType.PING)
send(packet.getAddress(), packet.getPort(), packet.getData());
else
packetReceiver.receivePacket(type, packet);
}
}
}
+3 -8
View File
@@ -27,21 +27,16 @@
***********************************************************************************/
package services.network;
import resources.Galaxy;
import resources.control.Manager;
public class NetworkManager extends Manager {
private NetworkListenerService netListenerService;
private NetworkClientManager netClientManager;
private final NetworkClientManager netClientManager;
public NetworkManager(Galaxy galaxy) {
netListenerService = new NetworkListenerService(galaxy);
netClientManager = new NetworkClientManager(netListenerService);
netListenerService.setPacketReceiver(netClientManager);
public NetworkManager() {
netClientManager = new NetworkClientManager();
addChildService(netClientManager);
addChildService(netListenerService);
}
}
+126 -83
View File
@@ -1,10 +1,11 @@
package services.objects;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
@@ -23,7 +24,6 @@ import resources.control.Service;
import resources.objects.SWGObject;
import resources.objects.cell.CellObject;
import resources.objects.creature.CreatureObject;
import resources.server_info.Config;
import resources.server_info.Log;
import resources.server_info.RelationalServerData;
import resources.server_info.RelationalServerFactory;
@@ -31,37 +31,24 @@ import resources.server_info.RelationalServerFactory;
public class ClientBuildoutService extends Service {
private static final String GET_BUILDOUT_AREAS = "SELECT * FROM areas ORDER BY area_name ASC, event ASC";
private static final String GET_CLIENT_OBJECTS_SQL = "SELECT objects.*, areas.terrain "
+ "FROM objects, areas "
+ "WHERE objects.area_id = areas.id "
private static final String GET_CLIENT_OBJECTS_SQL = "SELECT objects.id, objects.area_id, objects.template_crc, objects.container_id, "
+ "objects.x, objects.y, objects.z, objects.orientation_x, objects.orientation_y, objects.orientation_z, objects.orientation_w, "
+ "objects.radius, objects.cell_index "
+ "FROM objects "
+ "ORDER BY buildout_id ASC";
private final CrcStringTableData strings;
private final RelationalServerData clientSdb;
private final List<BuildoutArea> areas;
private final Map<Integer, BuildoutArea> areasById;
private final PreparedStatement getClientObjects;
public ClientBuildoutService() {
strings = (CrcStringTableData) ClientFactory.getInfoFromFile("misc/object_template_crc_string_table.iff");
clientSdb = RelationalServerFactory.getServerData("buildout/buildouts.db", "areas", "objects");
if (clientSdb == null)
throw new main.ProjectSWG.CoreException("Unable to load sdb files for ClientObjectLoader");
areas = new ArrayList<>();
areasById = new Hashtable<>(1000); // Number of buildout areas
getClientObjects = clientSdb.prepareStatement(GET_CLIENT_OBJECTS_SQL);
registerForIntent(PlayerTransformedIntent.TYPE);
}
@Override
public boolean initialize() {
List<String> events = getEvents();
loadAreas(events);
return super.initialize();
}
@Override
public void onIntentReceived(Intent i) {
switch (i.getType()) {
@@ -74,40 +61,72 @@ public class ClientBuildoutService extends Service {
}
}
public Map<Long, SWGObject> loadClientObjects() {
Config c = getConfig(ConfigFile.PRIMARY);
if (c.getBoolean("LOAD-OBJECTS", true)) {
System.out.println("ClientBuildoutService: Loading client objects...");
Log.i("ClientBuildoutService", "Loading client objects...");
long startLoad = System.nanoTime();
Map<Long, SWGObject> objects = new Hashtable<>(4*1024);
loadClientObjects(objects);
double loadTime = (System.nanoTime() - startLoad) / 1E6;
System.out.printf("ClientObjectLoader: Finished loading %d client objects. Time: %fms%n", objects.size(), loadTime);
Log.i("ClientObjectLoader", "Finished loading %d client objects. Time: %fms", objects.size(), loadTime);
return objects;
} else {
Log.w("ClientObjectLoader", "Did not load client objects. Reason: Disabled.");
System.out.println("ClientObjectLoader: Did not load client objects. Reason: Disabled!");
public Collection<SWGObject> loadClientObjects() {
Collection<SWGObject> objects;
long startLoad = System.nanoTime();
logInfo("Loading client objects...");
try {
loadAreas(getEvents());
if (getConfig(ConfigFile.PRIMARY).getBoolean("LOAD-OBJECTS", true))
objects = loadObjects();
else
objects = new HashSet<>();
} catch (SQLException e) {
objects = new HashSet<>();
e.printStackTrace();
Log.e(this, e);
}
return new HashMap<>();
double loadTime = (System.nanoTime() - startLoad) / 1E6;
logInfo("Finished loading %d client objects. Time: %fms", objects.size(), loadTime);
return objects;
}
private void loadClientObjects(Map<Long, SWGObject> objects) {
try (ResultSet set = getClientObjects.executeQuery()) {
set.setFetchSize(1500);
BuildoutArea area = null;
ColumnIndexes ind = new ColumnIndexes(set);
SWGObject obj;
Location l = new Location();
while (set.next()) {
area = areasById.get(ind.areaInd);
obj = createObject(set, objects, l, area, ind);
objects.put(obj.getObjectId(), obj);
private Collection<SWGObject> loadObjects() throws SQLException {
Map<Long, SWGObject> objects = new Hashtable<>();
try (RelationalServerData data = RelationalServerFactory.getServerData("buildout/buildouts.db", "objects")) {
try (ResultSet set = data.executeQuery(GET_CLIENT_OBJECTS_SQL)) {
set.setFetchSize(4*1024);
BuildoutArea area = null;
ObjectInformation info = new ObjectInformation(set);
int prevAreaId = Integer.MAX_VALUE;
int areaId = 0;
while (set.next()) {
areaId = info.getAreaIdNoLoad();
if (prevAreaId != areaId) {
area = areasById.get(areaId);
prevAreaId = areaId;
}
if (area == null)
continue;
info.load(strings);
createObject(objects, area, info);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return Collections.unmodifiableCollection(objects.values());
}
private void createObject(Map<Long, SWGObject> objects, BuildoutArea area, ObjectInformation info) throws SQLException {
SWGObject obj = ObjectCreator.createObjectFromTemplate(info.getId(), info.getTemplate());
Location l = info.getLocation();
l.setTerrain(area.getTerrain());
obj.setLocation(l);
obj.setBuildout(true);
obj.setBuildoutArea(area);
obj.setLoadRange(info.getRadius());
checkCell(obj, info.getCell());
checkChild(objects, obj, info.getContainer());
objects.put(obj.getObjectId(), obj);
}
private void checkCell(SWGObject obj, int cell) {
if (cell != 0 && obj instanceof CellObject)
((CellObject) obj).setNumber(cell);
}
private void checkChild(Map<Long, SWGObject> objects, SWGObject obj, long container) {
if (container != 0)
objects.get(container).addObject(obj);
}
private List<String> getEvents() {
@@ -122,37 +141,20 @@ public class ClientBuildoutService extends Service {
return events;
}
private SWGObject createObject(ResultSet set, Map<Long, SWGObject> objects, Location l, BuildoutArea area, ColumnIndexes ind) throws SQLException {
SWGObject obj = ObjectCreator.createObjectFromTemplate(set.getLong(ind.idInd), strings.getTemplateString(set.getInt(ind.crcInd)));
l.setTerrain(Terrain.getTerrainFromName(set.getString(ind.terInd)));
l.setPosition(set.getDouble(ind.xInd), set.getDouble(ind.yInd), set.getDouble(ind.zInd));
l.setOrientation(set.getDouble(ind.oxInd), set.getDouble(ind.oyInd), set.getDouble(ind.ozInd), set.getDouble(ind.owInd));
obj.setLocation(l);
obj.setBuildout(true);
obj.setBuildoutArea(area);
obj.setLoadRange(set.getInt(ind.radiusInd));
int cell = set.getInt(ind.cellInd);
if (cell != 0 && obj instanceof CellObject)
((CellObject) obj).setNumber(cell);
long container = set.getLong(ind.contInd);
if (container != 0)
objects.get(container).addObject(obj);
return obj;
}
private void loadAreas(List <String> events) {
private void loadAreas(List <String> events) throws SQLException {
BuildoutArea primary = null; // Stored as "best area" for what we want to load
try (RelationalServerData data = RelationalServerFactory.getServerData("buildout/buildouts.db", "areas")) {
try (ResultSet set = data.prepareStatement(GET_BUILDOUT_AREAS).executeQuery()) {
try (RelationalServerData data = RelationalServerFactory.getServerData("buildout/areas.db", "areas")) {
try (ResultSet set = data.executeQuery(GET_BUILDOUT_AREAS)) {
areas.clear();
areasById.clear();
AreaIndexes ind = new AreaIndexes(set);
boolean loaded = false;
while (set.next()) {
BuildoutArea area = createArea(set, ind);
area.setLoaded(false);
if (area.getEvent().isEmpty() && (primary == null || !area.getName().equals(primary.getName()))) {
if (!loaded && primary != null)
loadArea(primary);
loadArea(area);
loaded = false;
primary = area; // Primary area, no event
}
@@ -164,11 +166,15 @@ public class ClientBuildoutService extends Service {
if (!loaded && primary != null)
loadArea(primary);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private void loadArea(BuildoutArea area) {
area.setLoaded(true);
areas.add(area);
areasById.put(area.getId(), area);
}
private void handlePlayerTransform(PlayerTransformedIntent pti) {
CreatureObject creature = pti.getPlayer();
Location world = creature.getWorldLocation();
@@ -179,11 +185,6 @@ public class ClientBuildoutService extends Service {
}
}
private void loadArea(BuildoutArea area) {
areas.add(area);
areasById.put(area.getId(), area);
}
private BuildoutArea createArea(ResultSet set, AreaIndexes ind) throws SQLException {
BuildoutAreaBuilder bldr = new BuildoutAreaBuilder()
.setId(set.getInt(ind.id))
@@ -235,6 +236,11 @@ public class ClientBuildoutService extends Service {
return (low + high) / 2;
}
private void logInfo(String message, Object ... args) {
System.out.printf(getClass().getSimpleName() + ": " + message + "%n", args);
Log.i(this, message, args);
}
private static class AreaIndexes {
private int id;
@@ -258,11 +264,49 @@ public class ClientBuildoutService extends Service {
}
private static class ObjectInformation {
private final ColumnIndexes index;
private final ResultSet set;
private final Location l;
private long id;
private String template;
private float radius;
private long container;
private int cell;
public ObjectInformation(ResultSet set) throws SQLException {
this.set = set;
index = new ColumnIndexes(set);
l = new Location();
}
public void load(CrcStringTableData strings) throws SQLException {
id = set.getLong(index.idInd);
template = strings.getTemplateString(set.getInt(index.crcInd));
l.setPosition(set.getDouble(index.xInd), set.getDouble(index.yInd), set.getDouble(index.zInd));
l.setOrientation(set.getDouble(index.oxInd), set.getDouble(index.oyInd), set.getDouble(index.ozInd), set.getDouble(index.owInd));
radius = set.getInt(index.radiusInd);
container = set.getLong(index.contInd);
cell = set.getInt(index.cellInd);
}
public int getAreaIdNoLoad() throws SQLException {
return set.getInt(index.areaInd);
}
public long getId() { return id; }
public String getTemplate() { return template; }
public Location getLocation() { return l; }
public double getRadius() { return radius; }
public long getContainer() { return container; }
public int getCell() { return cell; }
}
private static class ColumnIndexes {
public final int idInd;
public final int crcInd;
public final int terInd;
public final int areaInd;
public final int xInd;
public final int yInd;
@@ -277,8 +321,7 @@ public class ClientBuildoutService extends Service {
public ColumnIndexes(ResultSet set) throws SQLException {
idInd = set.findColumn("id");
crcInd = set.findColumn("templateCrc");
terInd = set.findColumn("terrain");
crcInd = set.findColumn("template_crc");
areaInd = set.findColumn("area_id");
xInd = set.findColumn("x");
yInd = set.findColumn("y");
@@ -288,8 +331,8 @@ public class ClientBuildoutService extends Service {
ozInd = set.findColumn("orientation_z");
owInd = set.findColumn("orientation_w");
radiusInd = set.findColumn("radius");
contInd = set.findColumn("containerId");
cellInd = set.findColumn("cellIndex");
contInd = set.findColumn("container_id");
cellInd = set.findColumn("cell_index");
}
}
+116 -69
View File
@@ -28,10 +28,11 @@
package services.objects;
import intents.PlayerEventIntent;
import intents.RequestZoneInIntent;
import intents.network.GalacticPacketIntent;
import intents.object.ObjectCreateIntent;
import intents.object.ObjectCreatedIntent;
import intents.object.ObjectTeleportIntent;
import intents.object.UpdateObjectAwareness;
import intents.player.PlayerTransformedIntent;
import java.util.HashMap;
@@ -40,14 +41,11 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import main.ProjectSWG;
import network.packets.Packet;
import network.packets.swg.zone.UpdateContainmentMessage;
import network.packets.swg.zone.insertion.CmdStartScene;
import network.packets.swg.zone.object_controller.DataTransform;
import network.packets.swg.zone.object_controller.DataTransformWithParent;
import resources.Location;
import resources.Race;
import resources.Terrain;
import resources.buildout.BuildoutArea;
import resources.control.Intent;
@@ -55,9 +53,8 @@ import resources.control.Service;
import resources.objects.SWGObject;
import resources.objects.creature.CreatureObject;
import resources.objects.quadtree.QuadTree;
import resources.objects.staticobject.StaticObject;
import resources.objects.tangible.TangibleObject;
import resources.player.Player;
import resources.player.PlayerEvent;
import resources.server_info.Log;
public class ObjectAwareness extends Service {
@@ -70,10 +67,10 @@ public class ObjectAwareness extends Service {
public ObjectAwareness() {
quadTree = new HashMap<Terrain, QuadTree<SWGObject>>();
registerForIntent(PlayerEventIntent.TYPE);
registerForIntent(ObjectCreateIntent.TYPE);
registerForIntent(ObjectCreatedIntent.TYPE);
registerForIntent(ObjectTeleportIntent.TYPE);
registerForIntent(GalacticPacketIntent.TYPE);
registerForIntent(UpdateObjectAwareness.TYPE);
loadQuadTree();
}
@@ -84,10 +81,6 @@ public class ObjectAwareness extends Service {
if (i instanceof PlayerEventIntent)
handlePlayerEventIntent((PlayerEventIntent) i);
break;
case ObjectCreateIntent.TYPE:
if (i instanceof ObjectCreateIntent)
handleObjectCreateIntent((ObjectCreateIntent) i);
break;
case ObjectCreatedIntent.TYPE:
if (i instanceof ObjectCreatedIntent)
handleObjectCreatedIntent((ObjectCreatedIntent) i);
@@ -100,6 +93,9 @@ public class ObjectAwareness extends Service {
if (i instanceof GalacticPacketIntent)
processGalacticPacketIntent((GalacticPacketIntent) i);
break;
case UpdateObjectAwareness.TYPE:
if (i instanceof UpdateObjectAwareness)
processUpdateObjectAwarenessIntent((UpdateObjectAwareness) i);
default:
break;
}
@@ -112,19 +108,15 @@ public class ObjectAwareness extends Service {
return;
switch (pei.getEvent()) {
case PE_DISAPPEAR:
creature.clearAware();
remove(creature);
for (SWGObject obj : creature.getObservers())
creature.destroyObject(obj.getOwner());
creature.clearAware();
creature.setOwner(null);
p.setCreatureObject(null);
break;
case PE_FIRST_ZONE:
if (creature.getParent() == null)
creature.createObject(p);
break;
case PE_ZONE_IN:
creature.clearAware();
creature.clearAware(false);
update(creature);
break;
default:
@@ -132,32 +124,26 @@ public class ObjectAwareness extends Service {
}
}
private void handleObjectCreateIntent(ObjectCreateIntent oci) {
SWGObject obj = oci.getObject();
if (isInAwareness(obj))
add(obj);
}
private void handleObjectCreatedIntent(ObjectCreatedIntent oci) {
SWGObject obj = oci.getObject();
if (isInAwareness(obj))
add(obj);
SWGObject object = oci.getObject();
if (isInAwareness(object)) {
add(object);
update(object);
}
}
private void processObjectTeleportIntent(ObjectTeleportIntent oti) {
SWGObject object = oti.getObject();
Player owner = object.getOwner();
boolean creature = object instanceof CreatureObject && owner != null;
Location old = object.getLocation();
object.setLocation(oti.getNewLocation());
if (oti.getParent() != null) {
if (creature)
startScene((CreatureObject) object, oti.getNewLocation());
move(object, oti.getParent(), oti.getNewLocation());
move(object, oti.getParent(), oti.getNewLocation(), false);
} else {
if (creature)
startScene((CreatureObject) object, oti.getNewLocation());
object.createObject(owner);
move(object, oti.getNewLocation());
moveFromOld(object, old, false);
}
if (object instanceof CreatureObject && ((CreatureObject) object).isLoggedInPlayer())
new RequestZoneInIntent(owner, (CreatureObject) object, false).broadcast();
}
private void processGalacticPacketIntent(GalacticPacketIntent i) {
@@ -165,39 +151,61 @@ public class ObjectAwareness extends Service {
if (packet instanceof DataTransform) {
DataTransform trans = (DataTransform) packet;
SWGObject obj = i.getObjectManager().getObjectById(trans.getObjectId());
moveObject(obj, trans);
if (obj instanceof CreatureObject)
moveObject((CreatureObject) obj, trans);
} else if (packet instanceof DataTransformWithParent) {
DataTransformWithParent transformWithParent = (DataTransformWithParent) packet;
SWGObject object = i.getObjectManager().getObjectById(transformWithParent.getObjectId());
SWGObject parent = i.getObjectManager().getObjectById(transformWithParent.getCellId());
moveObject(object, parent, transformWithParent);
if (object instanceof CreatureObject)
moveObject((CreatureObject) object, parent, transformWithParent);
}
}
private void startScene(CreatureObject object, Location newLocation) {
long time = (long) (ProjectSWG.getCoreTime() / 1E3);
Race race = ((CreatureObject)object).getRace();
sendPacket(object.getOwner(), new CmdStartScene(false, object.getObjectId(), race, newLocation, time, (int)(System.currentTimeMillis()/1E3)));
new PlayerEventIntent(object.getOwner(), PlayerEvent.PE_ZONE_IN).broadcast();
private void processUpdateObjectAwarenessIntent(UpdateObjectAwareness i) {
SWGObject obj = i.getObject();
Location l = obj.getLocation();
QuadTree <SWGObject> tree = getTree(l);
List<SWGObject> objects;
synchronized (tree) {
objects = tree.get(l.getX(), l.getZ());
}
Log.d(this, "Updated awareness for %s", obj);
if (objects.contains(obj)) {
if (!i.isInAwareness()) {
remove(obj);
obj.clearAware(false);
}
return;
}
add(obj);
update(obj);
}
private void moveObject(SWGObject obj, DataTransform transform) {
private void moveObject(CreatureObject obj, DataTransform transform) {
Location newLocation = transform.getLocation();
newLocation.setTerrain(obj.getTerrain());
double time = ((CreatureObject) obj).getTimeSinceLastTransform() / 1000;
obj.updateLastTransformTime();
Location l = obj.getWorldLocation();
double speed = Math.sqrt(square(l.getX()-newLocation.getX()) + square(l.getZ()-newLocation.getZ())) / time;
if (speed > obj.getMovementScale()*7.3) {
double angle = (newLocation.getX() == l.getX() ? 0 : Math.atan2(newLocation.getZ()-l.getZ(), newLocation.getX()-l.getX()));
newLocation.setX(l.getX()+obj.getMovementScale()*7.3*time*Math.cos(angle));
newLocation.setZ(l.getZ()+obj.getMovementScale()*7.3*time*Math.sin(angle));
transform.setSpeed((float) (obj.getMovementScale()*7.3));
}
BuildoutArea area = obj.getBuildoutArea();
if (area != null && area.isAdjustCoordinates())
newLocation.translatePosition(area.getX1(), 0, area.getZ1());
if (obj instanceof CreatureObject)
new PlayerTransformedIntent((CreatureObject) obj, obj.getParent(), null, obj.getLocation(), newLocation).broadcast();
move(obj, newLocation);
new PlayerTransformedIntent(obj, obj.getParent(), null, obj.getLocation(), newLocation).broadcast();
move(obj, newLocation, true);
if (area != null && area.isAdjustCoordinates())
newLocation.translatePosition(-area.getX1(), 0, -area.getZ1());
obj.sendDataTransforms(transform);
// TODO: State checks before sending a data transform message to ensure the move is valid
}
private void moveObject(SWGObject obj, SWGObject parent, DataTransformWithParent transformWithParent) {
private void moveObject(CreatureObject obj, SWGObject parent, DataTransformWithParent transformWithParent) {
Location newLocation = transformWithParent.getLocation();
newLocation.setTerrain(obj.getTerrain());
if (parent == null) {
@@ -205,9 +213,20 @@ public class ObjectAwareness extends Service {
Log.e("ObjectManager", "Could not find parent for transform! Cell: %d Object: %s", transformWithParent.getCellId(), obj);
return;
}
if (obj instanceof CreatureObject)
new PlayerTransformedIntent((CreatureObject) obj, obj.getParent(), parent, obj.getLocation(), newLocation).broadcast();
move(obj, parent, newLocation);
double time = ((CreatureObject) obj).getTimeSinceLastTransform() / 1000;
obj.updateLastTransformTime();
Location l = obj.getWorldLocation();
Location nWorld = new Location(newLocation.getX(), 0, newLocation.getZ(), parent.getTerrain());
nWorld.translateLocation(parent.getWorldLocation());
double speed = Math.sqrt(square(l.getX()-nWorld.getX()) + square(l.getZ()-nWorld.getZ())) / time;
if (speed > obj.getMovementScale()*7.3) {
double angle = (nWorld.getX() == l.getX() ? 0 : Math.atan2(nWorld.getZ()-l.getZ(), nWorld.getX()-l.getX())) + Math.PI;
newLocation.setX(newLocation.getX()+obj.getMovementScale()*7.3*time*invertNormalizedValue(Math.cos(angle)));
newLocation.setZ(newLocation.getZ()+obj.getMovementScale()*7.3*time*invertNormalizedValue(Math.sin(angle)));
transformWithParent.setSpeed((float) (obj.getMovementScale()*7.3));
}
new PlayerTransformedIntent((CreatureObject) obj, obj.getParent(), parent, obj.getLocation(), newLocation).broadcast();
move(obj, parent, newLocation, true);
obj.sendParentDataTransforms(transformWithParent);
}
@@ -218,7 +237,13 @@ public class ObjectAwareness extends Service {
}
private boolean isInAwareness(SWGObject object) {
return object.getParent() == null && !(object instanceof StaticObject);
return object.getParent() == null && object instanceof TangibleObject;
}
private double invertNormalizedValue(double x) {
if (x < 0)
return -1 - x;
return 1-x;
}
/**
@@ -226,7 +251,6 @@ public class ObjectAwareness extends Service {
* @param object the object to add
*/
public void add(SWGObject object) {
update(object);
Location l = object.getLocation();
if (invalidLocation(l))
return;
@@ -241,13 +265,7 @@ public class ObjectAwareness extends Service {
* @param object the object to remove
*/
public void remove(SWGObject object) {
Location l = object.getLocation();
if (invalidLocation(l))
return;
QuadTree <SWGObject> tree = getTree(l);
synchronized (tree) {
tree.remove(l.getX(), l.getZ(), object);
}
removeFromLocation(object, object.getLocation());
}
/**
@@ -255,8 +273,9 @@ public class ObjectAwareness extends Service {
* includes moving from a cell to the world.
* @param object the object to move
* @param nLocation the new location
* @param update boolean on whether or not to update the object's awareness
*/
public void move(SWGObject object, Location nLocation) {
private void move(SWGObject object, Location nLocation, boolean update) {
if (object.getParent() != null) {
object.getParent().removeObject(object); // Moving from cell to world
object.sendObserversAndSelf(new UpdateContainmentMessage(object.getObjectId(), 0, object.getSlotArrangement()));
@@ -265,6 +284,8 @@ public class ObjectAwareness extends Service {
}
object.setLocation(nLocation);
add(object);
if (update)
update(object);
}
/**
@@ -274,8 +295,9 @@ public class ObjectAwareness extends Service {
* @param object the object to move
* @param nParent the new parent the object will be in
* @param nLocation the new location relative to the parent
* @param update boolean on whether or not to update the object's awareness
*/
public void move(SWGObject object, SWGObject nParent, Location nLocation) {
private void move(SWGObject object, SWGObject nParent, Location nLocation, boolean update) {
SWGObject parent = object.getParent();
if (parent != null && nParent != parent) {
parent.removeObject(object); // Moving from cell to cell, for instance
@@ -287,7 +309,8 @@ public class ObjectAwareness extends Service {
object.sendObserversAndSelf(new UpdateContainmentMessage(object.getObjectId(), nParent.getObjectId(), object.getSlotArrangement()));
}
object.setLocation(nLocation);
update(object);
if (update)
update(object);
}
/**
@@ -295,7 +318,7 @@ public class ObjectAwareness extends Service {
* the awareness is up to date
* @param obj the object to update
*/
public void update(SWGObject obj) {
private void update(SWGObject obj) {
if (obj.isBuildout())
return;
Location l = obj.getWorldLocation();
@@ -303,16 +326,38 @@ public class ObjectAwareness extends Service {
return;
Set <SWGObject> objectAware = new HashSet<SWGObject>();
QuadTree <SWGObject> tree = getTree(l);
List <SWGObject> range;
synchronized (tree) {
List <SWGObject> range = tree.getWithinRange(l.getX(), l.getZ(), AWARE_RANGE);
for (SWGObject inRange : range) {
if (isValidInRange(obj, inRange, l))
objectAware.add(inRange);
}
range = tree.getWithinRange(l.getX(), l.getZ(), AWARE_RANGE);
}
for (SWGObject inRange : range) {
if (isValidInRange(obj, inRange, l))
objectAware.add(inRange);
}
obj.updateObjectAwareness(objectAware);
}
private void moveFromOld(SWGObject object, Location oldLocation, boolean update) {
if (object.getParent() != null) {
object.getParent().removeObject(object); // Moving from cell to world
object.sendObserversAndSelf(new UpdateContainmentMessage(object.getObjectId(), 0, object.getSlotArrangement()));
} else {
removeFromLocation(object, oldLocation); // World to World
}
add(object);
if (update)
update(object);
}
private void removeFromLocation(SWGObject object, Location l) {
if (invalidLocation(l))
return;
QuadTree <SWGObject> tree = getTree(l);
synchronized (tree) {
tree.remove(l.getX(), l.getZ(), object);
}
}
private QuadTree <SWGObject> getTree(Location l) {
return quadTree.get(l.getTerrain());
}
@@ -324,6 +369,8 @@ public class ObjectAwareness extends Service {
private boolean isValidInRange(SWGObject obj, SWGObject inRange, Location objLoc) {
if (inRange.getObjectId() == obj.getObjectId())
return false;
if (obj instanceof CreatureObject && ((CreatureObject) obj).isLoggedOutPlayer())
return false;
int distSquared = distanceSquared(objLoc, inRange.getWorldLocation());
int loadSquared = (int) (square(inRange.getLoadRange()) + 0.5);
return (loadSquared != 0 || distSquared <= DEFAULT_LOAD_RANGE) && (loadSquared == 0 || distSquared <= loadSquared);
+51 -22
View File
@@ -31,6 +31,7 @@ import java.util.Map.Entry;
import resources.client_info.ClientFactory;
import resources.client_info.visitors.ObjectData;
import resources.client_info.visitors.ObjectData.ObjectDataAttribute;
import resources.client_info.visitors.SlotArrangementData;
import resources.client_info.visitors.SlotDescriptorData;
import resources.objects.SWGObject;
@@ -51,21 +52,40 @@ import resources.objects.waypoint.WaypointObject;
import resources.objects.weapon.WeaponObject;
public final class ObjectCreator {
private static final Object OBJECT_ID_MUTEX = new Object();
private static long maxObjectId = 1;
public static void updateMaxObjectId(long objectId) {
synchronized (OBJECT_ID_MUTEX) {
if (objectId > maxObjectId)
maxObjectId = objectId;
}
}
public static SWGObject createObjectFromTemplate(long objectId, String template) {
if (!template.startsWith("object/"))
return null;
if (!template.endsWith(".iff"))
return null;
SWGObject obj = createObjectFromType(objectId, getFirstTemplatePart(template.substring(7, template.length()-7-4)));
SWGObject obj = createObjectFromType(objectId, getTemplatePart(template, 1));
if (obj == null)
return null;
obj.setTemplate(template);
handlePostCreation(obj);
updateMaxObjectId(objectId);
return obj;
}
public static SWGObject createObjectFromTemplate(String template) {
long id = 0;
synchronized (OBJECT_ID_MUTEX) {
id = maxObjectId++;
}
return createObjectFromTemplate(id, template);
}
private static SWGObject createObjectFromType(long objectId, String type) {
switch (type) {
case "building": return new BuildingObject(objectId);
@@ -84,7 +104,7 @@ public final class ObjectCreator {
case "tangible": return new TangibleObject(objectId);
case "waypoint": return new WaypointObject(objectId);
case "weapon": return new WeaponObject(objectId);
default: return null;
default: System.err.println("Unknown type: " + type); return null;
}
}
@@ -99,27 +119,26 @@ public final class ObjectCreator {
if (attributes == null)
return;
for (Entry<String, Object> e : attributes.getAttributes().entrySet()) {
obj.setTemplateAttribute(e.getKey(), e.getValue());
setObjectAttribute(e.getKey(), e.getValue().toString(), obj);
for (Entry<ObjectDataAttribute, Object> e : attributes.getAttributes().entrySet()) {
setObjectAttribute(e.getKey(), e.getValue(), obj);
}
}
private static void setObjectAttribute(String key, String value, SWGObject object) {
switch(key) {
case ObjectData.OBJ_STF: object.setStringId(value); break;
case ObjectData.DETAIL_STF: object.setDetailStringId(value); break;
case ObjectData.VOLUME_LIMIT: object.setVolume(Integer.parseInt(value)); break;
case ObjectData.CONTAINER_TYPE: object.setContainerType(Integer.parseInt(value)); break;
private static void setObjectAttribute(ObjectDataAttribute key, Object value, SWGObject object) {
object.setDataAttribute(key, value);
switch (key) {
case OBJECT_NAME: object.setStringId(value.toString()); break;
case DETAILED_DESCRIPTION: object.setDetailStringId(value.toString()); break;
case CONTAINER_VOLUME_LIMIT: object.setVolume((Integer) value); break;
case CONTAINER_TYPE: object.setContainerType((Integer) value); break;
default: break;
}
}
private static void createObjectSlots(SWGObject object) {
if (object.getTemplateAttribute(ObjectData.SLOT_DESCRIPTOR) != null) {
if (object.getDataAttribute(ObjectDataAttribute.SLOT_DESCRIPTOR_FILENAME) != null) {
// These are the slots that the object *HAS*
SlotDescriptorData descriptor = (SlotDescriptorData) ClientFactory.getInfoFromFile((String) object.getTemplateAttribute(ObjectData.SLOT_DESCRIPTOR), true);
SlotDescriptorData descriptor = (SlotDescriptorData) ClientFactory.getInfoFromFile((String) object.getDataAttribute(ObjectDataAttribute.SLOT_DESCRIPTOR_FILENAME), true);
if (descriptor == null)
return;
@@ -128,9 +147,9 @@ public final class ObjectCreator {
}
}
if (object.getTemplateAttribute(ObjectData.ARRANGEMENT_FILE) != null) {
if (object.getDataAttribute(ObjectDataAttribute.ARRANGEMENT_DESCRIPTOR_FILENAME) != null) {
// This is what slots the created object is able to go into/use
SlotArrangementData arrangementData = (SlotArrangementData) ClientFactory.getInfoFromFile((String) object.getTemplateAttribute(ObjectData.ARRANGEMENT_FILE), true);
SlotArrangementData arrangementData = (SlotArrangementData) ClientFactory.getInfoFromFile((String) object.getDataAttribute(ObjectDataAttribute.ARRANGEMENT_DESCRIPTOR_FILENAME), true);
if (arrangementData == null)
return;
@@ -141,11 +160,21 @@ public final class ObjectCreator {
/*
Misc helper methods
*/
private static String getFirstTemplatePart(String template) {
int ind = template.indexOf('/');
if (ind == -1)
return "";
return template.substring(0, ind);
private static String getTemplatePart(String template, int index) {
int start = 0;
int end = 0;
for (int i = 0; i < template.length(); i++) {
if (template.charAt(i) != '/')
continue;
index--;
if (index == 0)
start = i+1;
else if (index == -1) {
end = i;
break;
}
}
return template.substring(start, end);
}
}
+61 -109
View File
@@ -27,19 +27,15 @@
***********************************************************************************/
package services.objects;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import intents.object.ObjectCreateIntent;
import intents.object.ObjectCreatedIntent;
import intents.object.ObjectIdRequestIntent;
import intents.object.ObjectIdResponseIntent;
import intents.object.ObjectTeleportIntent;
import intents.player.DeleteCharacterIntent;
import intents.RequestZoneInIntent;
@@ -49,7 +45,6 @@ import network.packets.swg.ErrorMessage;
import network.packets.swg.zone.SceneDestroyObject;
import network.packets.swg.zone.insertion.SelectCharacter;
import resources.Location;
import resources.containers.ContainerPermissions;
import resources.control.Intent;
import resources.control.Manager;
import resources.objects.SWGObject;
@@ -75,7 +70,6 @@ public class ObjectManager extends Manager {
private final ObjectDatabase<SWGObject> database;
private final Map <Long, SWGObject> objectMap;
private long maxObjectId;
public ObjectManager() {
objectAwareness = new ObjectAwareness();
@@ -87,7 +81,6 @@ public class ObjectManager extends Manager {
database = new CachedObjectDatabase<SWGObject>("odb/objects.db");
objectMap = new Hashtable<>(16*1024);
maxObjectId = 1;
addChildService(objectAwareness);
addChildService(mapManager);
@@ -98,8 +91,7 @@ public class ObjectManager extends Manager {
registerForIntent(GalacticPacketIntent.TYPE);
registerForIntent(ObjectTeleportIntent.TYPE);
registerForIntent(ObjectIdRequestIntent.TYPE);
registerForIntent(ObjectCreateIntent.TYPE);
registerForIntent(ObjectCreatedIntent.TYPE);
registerForIntent(DeleteCharacterIntent.TYPE);
}
@@ -114,55 +106,34 @@ public class ObjectManager extends Manager {
long startLoad = System.nanoTime();
Log.i("ObjectManager", "Loading objects from ObjectDatabase...");
System.out.println("ObjectManager: Loading objects from ObjectDatabase...");
database.load();
database.traverse(new Traverser<SWGObject>() {
@Override
public void process(SWGObject obj) {
loadObject(obj);
if (obj.getObjectId() >= maxObjectId) {
maxObjectId = obj.getObjectId() + 1;
synchronized (database) {
database.load();
database.traverse(new Traverser<SWGObject>() {
@Override
public void process(SWGObject obj) {
loadObject(obj);
}
}
});
});
}
double loadTime = (System.nanoTime() - startLoad) / 1E6;
Log.i("ObjectManager", "Finished loading %d objects. Time: %fms", database.size(), loadTime);
System.out.printf("ObjectManager: Finished loading %d objects. Time: %fms%n", database.size(), loadTime);
}
private void loadClientObjects() {
for (SWGObject obj : clientBuildoutService.loadClientObjects().values()) {
synchronized (objectMap) {
if (obj.getObjectId() >= maxObjectId) {
maxObjectId = obj.getObjectId() + 1;
}
}
objectMap.put(obj.getObjectId(), obj);
new ObjectCreatedIntent(obj).broadcast();
Collection<SWGObject> objects = clientBuildoutService.loadClientObjects();
for (SWGObject object : objects) {
putObject(object);
new ObjectCreatedIntent(object).broadcast();
}
}
private void loadObject(SWGObject obj) {
obj.setOwner(null);
// if player is not a player
if (!(obj instanceof CreatureObject && ((CreatureObject) obj).hasSlot("ghost")))
// if creature is not a player
if (!(obj instanceof CreatureObject && ((CreatureObject) obj).isLoggedOutPlayer()))
objectAwareness.add(obj);
if (obj instanceof CreatureObject && ((CreatureObject) obj).getPlayerObject() != null) {
if (!obj.hasSlot("bank")) {
SWGObject missing = createObject(obj, "object/tangible/bank/shared_character_bank.iff", false);
missing.setContainerPermissions(ContainerPermissions.INVENTORY);
}
if (!obj.hasSlot("mission_bag")) {
SWGObject missing = createObject(obj, "object/tangible/mission_bag/shared_mission_bag.iff", false);
missing.setContainerPermissions(ContainerPermissions.INVENTORY);
}
if (!obj.hasSlot("appearance_inventory")) {
SWGObject missing = createObject(obj, "object/tangible/inventory/shared_appearance_inventory.iff", false);
missing.setContainerPermissions(ContainerPermissions.INVENTORY);
}
}
objectMap.put(obj.getObjectId(), obj);
putObject(obj);
updateBuildoutParent(obj);
addChildrenObjects(obj);
}
@@ -172,7 +143,7 @@ public class ObjectManager extends Manager {
if (obj.getParent().isBuildout()) {
long id = obj.getParent().getObjectId();
obj.getParent().removeObject(obj);
SWGObject parent = objectMap.get(id);
SWGObject parent = getObjectById(id);
if (parent != null)
parent.addObject(obj);
else {
@@ -187,15 +158,17 @@ public class ObjectManager extends Manager {
private void addChildrenObjects(SWGObject obj) {
for (SWGObject child : obj.getContainedObjects()) {
objectMap.put(child.getObjectId(), child);
putObject(child);
addChildrenObjects(child);
}
}
@Override
public boolean terminate() {
database.traverse((obj) -> obj.setOwner(null));
database.close();
synchronized (database) {
database.traverse((obj) -> obj.setOwner(null));
database.close();
}
return super.terminate();
}
@@ -203,36 +176,23 @@ public class ObjectManager extends Manager {
public void onIntentReceived(Intent i) {
if (i instanceof GalacticPacketIntent) {
processGalacticPacketIntent((GalacticPacketIntent) i);
} else if (i instanceof ObjectIdRequestIntent) {
processObjectIdRequestIntent((ObjectIdRequestIntent) i);
} else if (i instanceof ObjectCreateIntent) {
processObjectCreateIntent((ObjectCreateIntent) i);
} else if (i instanceof ObjectCreatedIntent) {
processObjectCreatedIntent((ObjectCreatedIntent) i);
} else if (i instanceof DeleteCharacterIntent) {
deleteObject(((DeleteCharacterIntent) i).getCreature().getObjectId());
}
}
private void processObjectCreateIntent(ObjectCreateIntent intent) {
SWGObject object = intent.getObject();
objectMap.put(object.getObjectId(), object);
private void processObjectCreatedIntent(ObjectCreatedIntent intent) {
putObject(intent.getObject());
}
private void processObjectIdRequestIntent(ObjectIdRequestIntent intent) {
List<Long> reservedIds = new ArrayList<>();
for (int i = 0; i < intent.getAmount(); i++) {
reservedIds.add(getNextObjectId());
}
new ObjectIdResponseIntent(intent.getIdentifier(), reservedIds).broadcast();
}
private void processGalacticPacketIntent(GalacticPacketIntent gpi) {
Packet packet = gpi.getPacket();
if (packet instanceof SelectCharacter) {
PlayerManager pm = gpi.getPlayerManager();
String galaxy = gpi.getGalaxy().getName();
long characterId = ((SelectCharacter) packet).getCharacterId();
zoneInCharacter(pm, galaxy, gpi.getNetworkId(), characterId);
zoneInCharacter(pm, gpi.getNetworkId(), characterId);
}
}
@@ -243,20 +203,29 @@ public class ObjectManager extends Manager {
}
public SWGObject deleteObject(long objId) {
synchronized (database) {
database.remove(objId);
}
synchronized (objectMap) {
SWGObject obj = objectMap.remove(objId);
database.remove(objId);
if (obj == null)
return null;
obj.clearAware();
objectAwareness.remove(obj);
Log.i("ObjectManager", "Deleted object %d [%s]", obj.getObjectId(), obj.getTemplate());
Log.v("ObjectManager", "Deleted object %d [%s]", obj.getObjectId(), obj.getTemplate());
return obj;
}
}
private void putObject(SWGObject object) {
ObjectCreator.updateMaxObjectId(object.getObjectId());
synchronized (objectMap) {
objectMap.put(object.getObjectId(), object);
}
}
public SWGObject destroyObject(long objectId) {
SWGObject object = objectMap.get(objectId);
SWGObject object = getObjectById(objectId);
return (object != null ? destroyObject(object) : null);
}
@@ -321,34 +290,31 @@ public class ObjectManager extends Manager {
}
public SWGObject createObject(SWGObject parent, String template, Location l, boolean addToDatabase) {
synchronized (objectMap) {
long objectId = getNextObjectId();
SWGObject obj = ObjectCreator.createObjectFromTemplate(objectId, template);
if (obj == null) {
System.err.println("ObjectManager: Unable to create object with template " + template);
return null;
}
obj.setLocation(l);
objectMap.put(objectId, obj);
if (parent != null) {
parent.addObject(obj);
}
if (addToDatabase) {
database.put(objectId, obj);
}
Log.i("ObjectManager", "Created object %d [%s]", obj.getObjectId(), obj.getTemplate());
new ObjectCreatedIntent(obj).broadcast();
return obj;
SWGObject obj = ObjectCreator.createObjectFromTemplate(template);
if (obj == null) {
System.err.println("ObjectManager: Unable to create object with template " + template);
return null;
}
obj.setLocation(l);
if (parent != null) {
parent.addObject(obj);
}
synchronized (database) {
if (addToDatabase)
database.put(obj.getObjectId(), obj);
}
Log.v("ObjectManager", "Created object %d [%s]", obj.getObjectId(), obj.getTemplate());
new ObjectCreatedIntent(obj).broadcast();
return obj;
}
private void zoneInCharacter(PlayerManager playerManager, String galaxy, long netId, long characterId) {
private void zoneInCharacter(PlayerManager playerManager, long netId, long characterId) {
Player player = playerManager.getPlayerFromNetworkId(netId);
if (player == null) {
Log.e("ObjectManager", "Unable to zone in null player '%d'", netId);
return;
}
SWGObject creatureObj = objectMap.get(characterId);
SWGObject creatureObj = getObjectById(characterId);
if (creatureObj == null) {
System.err.println("ObjectManager: Failed to start zone - CreatureObject could not be fetched from database [Character: " + characterId + " User: " + player.getUsername() + "]");
Log.e("ObjectManager", "Failed to start zone - CreatureObject could not be fetched from database [Character: %d User: %s]", characterId, player.getUsername());
@@ -367,15 +333,7 @@ public class ObjectManager extends Manager {
sendClientFatal(player, "Failed to zone", "There has been an internal server error: Null Ghost.\nPlease delete your character and create a new one", 10, TimeUnit.SECONDS);
return;
}
if (creatureObj.getParent() != null) {
objectAwareness.update(creatureObj);
Log.d("ObjectManager", "Zoning in to %s/%s - %s", creatureObj.getParent(), creatureObj.getTerrain(), creatureObj.getLocation().getPosition());
}else {
objectAwareness.remove(creatureObj);
objectAwareness.add(creatureObj);
Log.d("ObjectManager", "Zoning in to %s - %s", creatureObj.getTerrain(), creatureObj.getLocation().getPosition());
}
new RequestZoneInIntent(player, (CreatureObject) creatureObj, galaxy).broadcast();
new RequestZoneInIntent(player, (CreatureObject) creatureObj, true).broadcast();
}
private void sendClientFatal(Player player, String title, String message, long timeToRead, TimeUnit time) {
@@ -390,10 +348,4 @@ public class ObjectManager extends Manager {
}, timeToRead, time);
}
private long getNextObjectId() {
synchronized (objectMap) {
return maxObjectId++;
}
}
}

Some files were not shown because too many files have changed in this diff Show More