Java tutorial
/******************************************************************************* * Copyright (c) 2013 <Project SWG> * * This File is part of NGECore2. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Using NGEngine to work with NGECore2 is making a combined work based on NGEngine. * Therefore all terms and conditions of the GNU Lesser General Public License cover the combination. ******************************************************************************/ package services.object; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.ByteOrder; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.TreeSet; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import resources.common.*; import resources.datatables.DisplayType; import resources.datatables.Options; import resources.datatables.PlayerFlags; import resources.equipment.Equipment; import resources.guild.Guild; import resources.harvest.SurveyTool; import org.apache.commons.lang3.text.WordUtils; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import org.python.antlr.PythonParser.list_for_return; import org.python.core.Py; import org.python.core.PyObject; import com.sleepycat.je.Transaction; import com.sleepycat.je.TransactionConfig; import com.sleepycat.persist.EntityCursor; import com.sleepycat.persist.model.Entity; import com.sleepycat.persist.model.PrimaryKey; import protocol.swg.CmdSceneReady; import protocol.swg.CmdStartScene; import protocol.swg.ErrorMessage; import protocol.swg.HeartBeatMessage; import protocol.swg.ObjControllerMessage; import protocol.swg.ParametersMessage; import protocol.swg.SelectCharacter; import protocol.swg.ServerTimeMessage; import protocol.swg.UnkByteFlag; import protocol.swg.chat.ChatFriendsListUpdate; import protocol.swg.chat.ChatOnChangeFriendStatus; import protocol.swg.chat.ChatOnConnectAvatar; import protocol.swg.chat.ChatOnGetFriendsList; import protocol.swg.chat.ChatRoomList; import protocol.swg.chat.ChatServerStatus; import protocol.swg.objectControllerObjects.ShowFlyText; import protocol.swg.chat.VoiceChatStatus; import protocol.swg.objectControllerObjects.UiPlayEffect; import engine.clientdata.ClientFileManager; import engine.clientdata.visitors.CrcStringTableVisitor; import engine.clientdata.visitors.DatatableVisitor; import engine.clientdata.visitors.WorldSnapshotVisitor; import engine.clientdata.visitors.WorldSnapshotVisitor.SnapshotChunk; import engine.clients.Client; import engine.resources.common.CRC; import engine.resources.container.Traverser; import engine.resources.container.WorldCellPermissions; import engine.resources.container.WorldPermissions; import engine.resources.database.DatabaseConnection; import engine.resources.database.ODBCursor; import engine.resources.database.ObjectDatabase; import engine.resources.objects.Delta; import engine.resources.objects.IPersistent; import engine.resources.objects.SWGObject; import engine.resources.scene.Planet; import engine.resources.scene.Point3D; import engine.resources.scene.Quaternion; import engine.resources.service.INetworkDispatch; import engine.resources.service.INetworkRemoteEvent; import main.NGECore; import resources.objectives.BountyMissionObjective; import resources.objects.SWGList; import resources.objects.building.BuildingObject; import resources.objects.cell.CellObject; import resources.objects.craft.DraftSchematic; import resources.objects.creature.CreatureObject; import resources.objects.factorycrate.FactoryCrateObject; import resources.objects.group.GroupObject; import resources.objects.guild.GuildObject; import resources.objects.harvester.HarvesterObject; import resources.objects.installation.InstallationObject; import resources.objects.intangible.IntangibleObject; import resources.objects.manufacture.ManufactureSchematicObject; import resources.objects.mission.MissionObject; import resources.objects.player.PlayerObject; import resources.objects.resource.GalacticResource; import resources.objects.resource.ResourceContainerObject; import resources.objects.resource.ResourceRoot; import resources.objects.staticobject.StaticObject; import resources.objects.tangible.TangibleObject; import resources.objects.waypoint.WaypointObject; import resources.objects.weapon.WeaponObject; import services.ai.AIActor; import services.command.BaseSWGCommand; import services.command.CombatCommand; import services.bazaar.AuctionItem; import services.chat.ChatRoom; import services.equipment.EquipmentService; import services.gcw.GCWPylon; import services.gcw.GCWSpawner; import services.spawn.MobileTemplate; import services.sui.SUIWindow; import services.sui.SUIWindow.SUICallback; import services.sui.SUIWindow.Trigger; @SuppressWarnings("unused") public class ObjectService implements INetworkDispatch { //private Map<Long, SWGObject> objectList = new ConcurrentHashMap<Long, SWGObject>(); private Map<Long, SWGObject> objectList = new ObjectList<Long, SWGObject>(); private Map<Long, List<CellObject>> cellMap = new HashMap<Long, List<CellObject>>(); private Map<Long, BuildingObject> buildingMap = new HashMap<Long, BuildingObject>(); private List<BuildingObject> persistentBuildings = new ArrayList<BuildingObject>(); private NGECore core; private DatabaseConnection databaseConnection; private AtomicLong highestId = new AtomicLong(); private Random random = new Random(); private Map<String, PyObject> serverTemplates = new ConcurrentHashMap<String, PyObject>(); private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); protected final Object objectMutex = new Object(); private List<Runnable> loadServerTemplateTasks = Collections.synchronizedList(new ArrayList<Runnable>()); private int iteratedReusedIds = 0; private List<Long> reusableIds = Collections.synchronizedList(new ArrayList<Long>()); private boolean buildoutDEBUG = false; public ObjectService(final NGECore core) { this.core = core; databaseConnection = core.getDatabase1(); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { synchronized (objectList) { for (SWGObject obj : objectList.values()) { if (obj.getClient() != null && obj.getClient().getSession() != null) { core.connectionService.disconnect(obj.getClient()); } } } core.bazaarService.saveAllItems(); core.housingService.saveBuildings(); core.harvesterService.saveHarvesters(); core.playerCityService.saveAllCities(); core.closeODBs(); System.out.println("Databases closed."); } }); long highestId; try { PreparedStatement ps = databaseConnection .preparedStatement("SELECT id FROM highestid WHERE id=(SELECT max(id) FROM highestid)"); ResultSet result = ps.executeQuery(); result.next(); highestId = result.getInt("id"); this.highestId.set(highestId); ps.close(); } catch (SQLException e) { e.printStackTrace(); } } public void loadObjects() { System.out.println("Loading objects..."); ODBCursor cursor = core.getSWGObjectODB().getCursor(); while (cursor.hasNext()) { SWGObject object = (SWGObject) cursor.next(); if (object != null && !(object instanceof BuildingObject) && !objectList.containsKey(object.getObjectID())) objectList.put(object.getObjectID(), object); } cursor.close(); // Has always to be closed properly or will create undefined locking behaviour! cursor = core.getReusableIdODB().getCursor(); while (cursor.hasNext()) { reusableIds.add(((ObjectId) cursor.next()).objectId); } loadBuildings(); cursor.close(); // Has always to be closed properly or will create undefined locking behaviour! System.out.println("Finished loading objects."); } private void loadBuildings() { ODBCursor cursor = core.getSWGObjectODB().getCursor(); while (cursor.hasNext()) { final SWGObject building = (SWGObject) cursor.next(); if (!(building instanceof BuildingObject) || building == null) continue; objectList.put(building.getObjectID(), building); Planet planet = core.terrainService.getPlanetByID(building.getPlanetId()); building.setPlanet(planet); building.viewChildren(building, true, true, (object) -> { if (!checkIfObjectAlreadyInList(object.getObjectID())) { objectList.put(object.getObjectID(), object); if (object.getParentId() != 0 && object.getContainer() == null) object.setParent(building); object.getContainerInfo(object.getTemplate()); } }); SWGObject sign = (SWGObject) building.getAttachment("sign"); if (sign != null) { sign.initializeBaselines(); sign.initAfterDBLoad(); objectList.put(sign.getObjectID(), sign); } if (building.getAttachment("structureOwner") != null && ((BuildingObject) building).getMaintenanceAmount() > 0) core.housingService.startMaintenanceTask((BuildingObject) building); } cursor.close(); } public void loadServerTemplates() { System.out.println("Loading server templates... (" + loadServerTemplateTasks.size() + " templates)"); loadServerTemplateTasks.forEach(Runnable::run); loadServerTemplateTasks.clear(); System.out.println("Finished loading server templates..."); } public SWGObject createObject(String Template, long objectID, Planet planet, Point3D position, Quaternion orientation, String customServerTemplate) { return createObject(Template, objectID, planet, position, orientation, customServerTemplate, false, true); } public SWGObject createObject(String Template, long objectID, Planet planet, Point3D position, Quaternion orientation, String customServerTemplate, boolean overrideSnapshot, boolean loadServerTemplate) { SWGObject object = null; CrcStringTableVisitor crcTable; try { crcTable = ClientFileManager.loadFile("misc/object_template_crc_string_table.iff", CrcStringTableVisitor.class); if (!crcTable.isValidCRC(CRC.StringtoCRC(Template))) { System.out.println("Invalid CRC for template:" + Template); return null; } } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } boolean isSnapshot = false; if (objectID != 0 && objectList.containsKey(objectID)) { System.err.println("Trying to create object with duplicate Id"); try { throw new Exception(); } catch (Exception e) { e.printStackTrace(); } } if (objectID == 0) { synchronized (objectMutex) { if (objectID == 0) objectID = generateObjectID(); if (!core.getObjectIdODB().contains(objectID)) core.getObjectIdODB().put(objectID, new ObjectId(objectID)); } } else isSnapshot = !overrideSnapshot; if (planet == null) { System.err.println("Planet is null in createObject for some reason."); try { throw new Exception(); } catch (Exception e) { e.printStackTrace(); } planet = core.terrainService.getPlanetByID(1); } if (Template.startsWith("object/creature")) { object = new CreatureObject(objectID, planet, position, orientation, Template); } else if (Template.startsWith("object/player")) { object = new PlayerObject(objectID, planet); } else if (Template.startsWith("object/tangible/survey_tool")) { object = new SurveyTool(objectID, planet, position, orientation, Template); } else if (Template.startsWith("object/tangible/destructible/shared_gcw_city_construction_beacon")) { float positionY = core.terrainService.getHeight(planet.getID(), position.x, position.z) - 1.5f; Point3D newpoint = new Point3D(position.x, positionY, position.z); object = new GCWPylon(objectID, planet, position, orientation, Template); } else if (Template .startsWith("object/tangible/loot/creature_loot/collections/shared_dejarik_table_base")) { float positionY = core.terrainService.getHeight(planet.getID(), position.x, position.z) + 0.3f; Point3D newpoint = new Point3D(position.x, positionY, position.z); object = new GCWSpawner(objectID, planet, position, orientation, Template); } else if (Template.startsWith("object/tangible/destructible/")) { // float positionY = core.terrainService.getHeight(planet.getID(), position.x, position.z)-1f; // Point3D newpoint = new Point3D(position.x,positionY,position.z); // object = new InstallationObject(objectID, planet, newpoint, orientation, Template); object = new TangibleObject(objectID, planet, position, orientation, Template); //object = new BuildingObject(objectID, planet, position, orientation, Template); } else if (Template.startsWith("object/tangible/gcw/static_base/shared_invisible_cloner")) { object = new BuildingObject(objectID, planet, position, orientation, Template); if (!isSnapshot && !overrideSnapshot && object.getPortalVisitor() != null) { int cellCount = object.getPortalVisitor().cells.size() - 1; // -1 for index 0 cell which is outside the building and used for ai pathfinding for (int i = 0; i < cellCount; i++) { CellObject cell = (CellObject) createObject("object/cell/shared_cell.iff", planet); cell.setCellNumber(i + 1); object.add(cell); } } } else if (Template.startsWith("object/tangible")) { object = new TangibleObject(objectID, planet, position, orientation, Template); } else if (Template.startsWith("object/intangible")) { if (Template.equals("object/intangible/buy_back/shared_buy_back_container.iff")) // Container sends TANO baselines but is in intangible folder.. lolsoe. object = new TangibleObject(objectID, planet, position, orientation, Template); else object = new IntangibleObject(objectID, planet, position, orientation, Template); } else if (Template.startsWith("object/weapon")) { object = new WeaponObject(objectID, planet, position, orientation, Template); } else if (Template.startsWith("object/building/player/construction")) { float positionY = core.terrainService.getHeight(planet.getID(), position.x, position.z) - 1f; Point3D newpoint = new Point3D(position.x, positionY, position.z); object = new InstallationObject(objectID, planet, newpoint, orientation, Template); } else if (Template.startsWith("object/building") || Template.startsWith("object/static/worldbuilding/structures") || Template.startsWith("object/static/structure")) { object = new BuildingObject(objectID, planet, position, orientation, Template); if (!isSnapshot && !overrideSnapshot && object.getPortalVisitor() != null) { int cellCount = object.getPortalVisitor().cells.size() - 1; // -1 for index 0 cell which is outside the building and used for ai pathfinding for (int i = 0; i < cellCount; i++) { CellObject cell = (CellObject) createObject("object/cell/shared_cell.iff", planet); cell.setCellNumber(i + 1); object.add(cell); } } } else if (Template.startsWith("object/cell")) { object = new CellObject(objectID, planet); } else if (Template.startsWith("object/static")) { object = new StaticObject(objectID, planet, position, orientation, Template); } else if (Template.startsWith("object/guild")) { object = new GuildObject(core, objectID, planet, position, orientation, Template); } else if (Template.startsWith("object/group")) { object = new GroupObject(objectID); } else if (Template.startsWith("object/mobile")) { object = new CreatureObject(objectID, planet, position, orientation, Template); } else if (Template.startsWith("object/waypoint")) { object = new WaypointObject(objectID, planet, position); } else if (Template.startsWith("object/mission")) { object = new MissionObject(objectID, planet, Template); } else if (Template.startsWith("object/resource_container")) { object = new ResourceContainerObject(objectID, planet, position, orientation, Template); } else if (Template.startsWith("object/factory/shared_factory_crate")) { object = new FactoryCrateObject(objectID, planet, position, orientation, Template); } else if (Template.startsWith("object/draft_schematic")) { object = new DraftSchematic(objectID, planet, Template, position, orientation); } else if (Template.startsWith("object/manufacture_schematic")) { object = new ManufactureSchematicObject(objectID, planet, Template, position, orientation); } else if (Template.startsWith("object/installation/mining_ore/construction")) { float positionY = core.terrainService.getHeight(planet.getID(), position.x, position.z) - 1f; Point3D newpoint = new Point3D(position.x, positionY, position.z); object = new InstallationObject(objectID, planet, newpoint, orientation, Template); } else if (Template.startsWith("object/installation/mining_ore") || Template.startsWith("object/installation/mining_liquid") || Template.startsWith("object/installation/mining_gas") || Template.startsWith("object/installation/mining_organic") || Template.startsWith("object/installation/generators")) { float positionY = core.terrainService.getHeight(planet.getID(), position.x, position.z) - 1f; Point3D newpoint = new Point3D(position.x, positionY, position.z); object = new HarvesterObject(objectID, planet, newpoint, orientation, Template); } else if (Template.startsWith("object/installation/turret")) { float positionY = core.terrainService.getHeight(planet.getID(), position.x, position.z); Point3D newpoint = new Point3D(position.x, positionY, position.z); object = new InstallationObject(objectID, planet, newpoint, orientation, Template); } else { return null; } if (planet != null) { object.setPlanetId(planet.getID()); } else { object.setPlanetId(0); } object.setAttachment("customServerTemplate", customServerTemplate); object.setisInSnapshot(isSnapshot); // Set Options - easier to set them across the board here // because we'll be spawning them despite most of them being unscripted. // Any such settings can be completely reset with setOptionsBitmask // in scripts and modified with setOptions(Options.X, true/false) if (Template.startsWith("object/creature/") || Template.startsWith("object/mobile/")) { if (Template.startsWith("object/mobile/beast_master/")) { ((CreatureObject) object).setOptionsBitmask(Options.NONE); } else if (Template.startsWith("object/mobile/vendor/")) { ((CreatureObject) object).setOptionsBitmask(Options.INVULNERABLE | Options.USABLE); } else if (Template.startsWith("object/mobile/vehicle/")) { ((CreatureObject) object).setOptionsBitmask(Options.ATTACKABLE | Options.MOUNT); } else if (Template.startsWith("object/mobile/hologram/")) { ((CreatureObject) object).setOptionsBitmask(Options.INVULNERABLE); } else if (Template.startsWith("object/mobile/")) { ((CreatureObject) object).setOptionsBitmask(Options.ATTACKABLE); } else if (Template.startsWith("object/creature/npc/theme_park/")) { ((CreatureObject) object).setOptionsBitmask(Options.INVULNERABLE); } else if (Template.startsWith("object/creature/npc/general/")) { ((CreatureObject) object).setOptionsBitmask(Options.INVULNERABLE | Options.CONVERSABLE); } else if (Template.startsWith("object/creature/droid/crafted/")) { ((CreatureObject) object).setOptionsBitmask(Options.NONE); } else if (Template.startsWith("object/creature/droid/")) { ((CreatureObject) object).setOptionsBitmask(Options.ATTACKABLE | Options.INVULNERABLE); } else if (Template.startsWith("object/creature/player/")) { ((CreatureObject) object).setOptionsBitmask(Options.ATTACKABLE); } } else if (object instanceof TangibleObject) { ((TangibleObject) object).setOptionsBitmask(Options.INVULNERABLE); if (Template.startsWith("object/tangible/vendor/")) { ((TangibleObject) object).setOptionsBitmask(Options.INVULNERABLE | Options.USABLE); } } if (loadServerTemplate) loadServerTemplate(object); else { final SWGObject pointer = object; loadServerTemplateTasks.add(() -> loadServerTemplate(pointer)); } SWGObject ret = objectList.put(objectID, object); //if (ret != null && !ret.getTemplate().equals(object.getTemplate())) { // if (ret == null) { // //System.err.println("ObjectService: Detected duplicate Id. Assigning new one.") // object = createObject(Template, objectID, planet, position, orientation, customServerTemplate, overrideSnapshot, loadServerTemplate); // } return object; } public void loadServerTemplate(SWGObject object) { String template = ((object.getAttachment("customServerTemplate") == null) ? object.getTemplate() : (object.getTemplate().split("shared_")[0] + "shared_" + ((String) object.getAttachment("customServerTemplate")) + ".iff")); String serverTemplate = template.replace(".iff", ""); // check if template is empty(4 default lines) to reduce RAM usage(saves about 500 MB of RAM) try { int numberOfLines = FileUtilities .getNumberOfLines("scripts/" + serverTemplate.split("shared_", 2)[0].replace("shared_", "") + serverTemplate.split("shared_", 2)[1] + ".py"); if (numberOfLines > 4) { if (serverTemplates.containsKey(template)) { PyObject func = serverTemplates.get(template); func.__call__(Py.java2py(core), Py.java2py(object)); } else { PyObject func = core.scriptService.getMethod( "scripts/" + serverTemplate.split("shared_", 2)[0].replace("shared_", ""), serverTemplate.split("shared_", 2)[1], "setup"); func.__call__(Py.java2py(core), Py.java2py(object)); serverTemplates.put(template, func); } } } catch (FileNotFoundException e) { System.out.println("!File Not Found:" + template.toString()); } catch (IOException e) { System.out.println("!IO error " + template.toString()); } object.setAttachment("hasLoadedServerTemplate", new Boolean(true)); } public SWGObject createObject(String Template, Planet planet) { return createObject(Template, 0, planet, new Point3D(0, 0, 0), new Quaternion(1, 0, 0, 0)); } public SWGObject createObject(String Template, Planet planet, String customServerTemplate) { return createObject(Template, 0, planet, new Point3D(0, 0, 0), new Quaternion(1, 0, 0, 0), customServerTemplate); } public SWGObject createObject(String Template, Planet planet, float x, float z, float y) { return createObject(Template, 0, planet, new Point3D(x, y, z), new Quaternion(1, 0, 0, 0)); } public SWGObject createObject(String Template, long objectID, Planet planet, Point3D position, Quaternion orientation) { return createObject(Template, objectID, planet, position, orientation, null); } public void addObjectToScene(SWGObject object) { core.simulationService.add(object, object.getPosition().x, object.getPosition().z); // TODO: Get Objects in range and contained objects, send packets, add to observer lists } public SWGObject getObject(long objectID) { SWGObject object = objectList.get(objectID); if (object == null) { if (objectList.containsKey(objectID)) { System.err.println("getObject(): object is null but objectList contains objectID key"); } else { //System.err.println("getObject(): object is null"); //Thread.currentThread().dumpStack(); } } return object; } public boolean checkIfObjectAlreadyInList(long objectID) { SWGObject object = objectList.get(objectID); if (object == null) return false; else return true; } public Map<Long, SWGObject> getObjectList() { return objectList; } public void destroyObject(final SWGObject object, int seconds) { scheduler.schedule(new Runnable() { @Override public void run() { try { destroyObject(object); } catch (Exception e) { e.printStackTrace(); } } }, seconds, TimeUnit.SECONDS); } public void destroyObject(SWGObject object) { if (object == null) { return; } if (object.getAttachment("AI") != null && object.getAttachment("AI") instanceof AIActor && ((AIActor) object.getAttachment("AI")).getMobileTemplate().getRespawnTime() > 0) { final long objectId = object.getObjectID(); final MobileTemplate Template = ((AIActor) object.getAttachment("AI")).getMobileTemplate(); final Planet planet = object.getPlanet(); final Point3D position = object.getPosition(); final Point3D spawnPosition = ((AIActor) object.getAttachment("AI")).getSpawnPosition(); final Quaternion orientation = object.getOrientation(); // final long cellId = ((object.getContainer() == null) ? 0L : object.getContainer().getObjectID()); CellObject cellO = spawnPosition.getCell(); final long cellId = ((cellO == null) ? 0L : cellO.getObjectID()); final short level = ((object instanceof CreatureObject) ? ((CreatureObject) object).getLevel() : (short) 0); scheduler.schedule(new Runnable() { @Override public void run() { try { // Commented for now until found where the respawn is always set to 60 for any NPC CreatureObject newObject = NGECore.getInstance().spawnService.spawnCreature(Template, 0, planet.getName(), cellId, spawnPosition.x, spawnPosition.y, spawnPosition.z, orientation.w, orientation.x, orientation.y, orientation.z, level); AIActor newAIActor = (AIActor) newObject.getAttachment("AI"); newAIActor.cloneActor(((AIActor) object.getAttachment("AI"))); ((AIActor) object.getAttachment("AI")).destroyActor(); //object.setAttachment("AI", null); } catch (Exception e) { e.printStackTrace(); } } }, ((AIActor) object.getAttachment("AI")).getMobileTemplate().getRespawnTime(), TimeUnit.SECONDS); //}, 30, TimeUnit.SECONDS); } String filePath = "scripts/" + object.getTemplate().split("shared_", 2)[0].replace("shared_", "") + object.getTemplate().split("shared_", 2)[1].replace(".iff", "") + ".py"; if (FileUtilities.doesFileExist(filePath)) { PyObject method = core.scriptService.getMethod( "scripts/" + object.getTemplate().split("shared_", 2)[0].replace("shared_", ""), object.getTemplate().split("shared_", 2)[1].replace(".iff", ""), "destroy"); if (method != null && method.isCallable()) { method.__call__(Py.java2py(core), Py.java2py(object)); } } if (object == null) { return; } object.viewChildren(object, true, true, new Traverser() { @Override public void process(SWGObject obj) { objectList.remove(obj.getObjectID()); } }); objectList.remove(object.getObjectID()); SWGObject parent = object.getContainer(); if (parent != null) { if (parent instanceof CreatureObject) { core.equipmentService.unequip((CreatureObject) parent, object); ((CreatureObject) parent).removeObjectFromEquipList(object); ((CreatureObject) parent).removeObjectFromAppearanceEquipList(object); } long parentId = object.getParentId(); parent.remove(object); object.setParentId(parentId); } else { if (!(object instanceof WaypointObject)) core.simulationService.remove(object, object.getWorldPosition().x, object.getWorldPosition().z, true); } @SuppressWarnings("unchecked") Vector<SWGObject> childObjects = (Vector<SWGObject>) object.getAttachment("childObjects"); if (childObjects != null) { for (SWGObject child : childObjects) { if (child != null && child.getParentId() != 0) destroyObject(child); } } } public void destroyObject(long objectID) { SWGObject object = getObject(objectID); if (object != null) { destroyObject(object); } } public SWGObject getObjectByCustomName(String customName) { if (customName == null) { return null; } synchronized (objectList) { for (SWGObject obj : objectList.values()) { if (obj.getCustomName() == null) continue; if (obj.getCustomName().equalsIgnoreCase(customName)) return obj; } } ODBCursor cursor = core.getSWGObjectODB().getCursor(); while (cursor.hasNext()) { SWGObject object = (SWGObject) cursor.next(); if (object == null) { continue; } if (object.getCustomName() != null && customName.length() > 0 && object.getCustomName().equalsIgnoreCase(customName)) { return object; } } cursor.close(); return null; } public SWGObject getObjectByFirstName(String customName) { if (customName == null) { return null; } if (customName.contains(" ")) customName = customName.split(" ")[0]; try { PreparedStatement ps = core.getDatabase1() .preparedStatement("SELECT id FROM characters WHERE \"firstName\" ILIKE ?"); ps.setString(1, customName); ResultSet resultSet = ps.executeQuery(); while (resultSet.next()) { long objectId = resultSet.getLong("id"); SWGObject object = getObject(objectId); if (object == null) object = getCreatureFromDB(objectId); return object; } } catch (SQLException e) { e.printStackTrace(); } return null; } public CreatureObject getCreatureFromDB(long objectId) { CreatureObject object = (CreatureObject) core.getSWGObjectODB().get(objectId); if (object != null) { loadServerTemplate(object); if (!checkIfObjectAlreadyInList(object.getObjectID())) objectList.put(object.getObjectID(), object); object.viewChildren(object, true, true, (child) -> loadServerTemplate(child)); object.viewChildren(object, true, true, (child) -> instantiateChild(child)); /* Diagnostic part */ // System.out.println("Creo : " + object.getCustomName()); // System.out.println("Creo ID : " + object.getObjectID()); // System.out.println("Equipment List : " + object.getEquipmentList().size()); /* Diagnostic part */ SWGList<Equipment> eqList = object.getEquipmentList(); List<Equipment> delList = new ArrayList<Equipment>(); for (Equipment eq : eqList) { // System.out.println("Equipment getObjectID() " + eq.getObjectId()); // System.out.println("Equipment Class " + eq.getObject().getClass()); -> NPE // System.out.println("Equipment Name " + eq.getObject().getCustomName()); -> NPE // System.out.println("Equipment Template " + eq.getObject().getTemplate()); -> NPE if (!checkIfObjectAlreadyInList(eq.getObjectId())) delList.add(eq); } eqList.removeAll(delList); // The persisted equipment list contains objects that do not exist anymore, merely a hotfix really } return object; } public void instantiateChild(SWGObject child) { // SWGObject object = (SWGObject) core.getSWGObjectODB().get(child); // createObject(String Template, long objectID, Planet planet, Point3D position, Quaternion orientation, String customServerTemplate) // System.out.println("childname : " + child.getCustomName()); // System.out.println("Child Class " + child.getClass()); if (!checkIfObjectAlreadyInList(child.getObjectID())) objectList.put(child.getObjectID(), child); // System.out.println("Child getObjectID() " + child.getObjectID()); // System.out.println("Child class " + child.getClass().getName()); } public long generateObjectID() { /*Random random = new Random(); long objectID = random.nextInt(); if(getObject(objectID) != null) return generateObjectID(); if(core.getCreatureODB().contains(new Long(objectID), Long.class, CreatureObject.class)) return generateObjectID(); return objectID;*/ // stack overflow when using recursion long newId = 0; //try { synchronized (objectMutex) { newId = highestId.incrementAndGet(); ObjectDatabase objectIdODB = core.getObjectIdODB(); while (objectList.containsKey(newId) || objectIdODB.contains(newId)) { newId = highestId.incrementAndGet(); } //System.out.println("Got an objid."); } /*final String sql = "UPDATE highestid SET id=? WHERE id=(SELECT MAX(id) FROM highestid)"; final PreparedStatement ps2 = databaseConnection.preparedStatement(sql); ps2.setLong(1, newId); ps2.executeUpdate(); ps2.close(); } catch (SQLException e) { e.printStackTrace(); }*/ return newId; } public long getDOId(String planet, String template, int type, long containerId, int cellNumber, float x1, float y, float z1) { SWGObject container = getObject(containerId); float x = ((container == null) ? x1 : container.getPosition().x + x1); float z = ((container == null) ? z1 : container.getPosition().z + z1); String key = "" + CRC.StringtoCRC(planet) + CRC.StringtoCRC(template) + type + containerId + cellNumber + x + y + z; long objectId = 0; boolean containsKey; synchronized (objectMutex) { containsKey = core.getDuplicateIdODB().contains(key); } if (containsKey) { synchronized (objectMutex) { objectId = ((DuplicateId) core.getDuplicateIdODB().get(key)).getObjectId(); } if (objectList.containsKey(objectId)) { System.err.println("Warning: DOId already in use. Using one from reusableId pool instead."); return getReusableId(); } } else { while (true) { objectId = generateObjectID(); synchronized (objectMutex) { if (!core.getObjectIdODB().contains(objectId)) { core.getObjectIdODB().put(objectId, new ObjectId(objectId)); } else { System.err.println("Error: Generated objectId is already in objectIdODB?"); System.err.println("Trying again..."); continue; } if (objectList.containsKey(objectId)) { System.err.println("Error: Generated objectId is already in objectList?"); System.err.println("Trying again..."); continue; } } break; } synchronized (objectMutex) { core.getDuplicateIdODB().put(key, new DuplicateId(key, objectId)); } } return objectId; } public long getReusableId() { long objectId = 0; synchronized (objectMutex) { objectId = reusableIds.iterator().next(); while (objectList.containsKey(objectId) && iteratedReusedIds++ < reusableIds.size()) { objectId = reusableIds.get(iteratedReusedIds); } if (objectList.containsKey(objectId)) { objectId = 0; } } if (objectId == 0) { while (true) { objectId = generateObjectID(); synchronized (objectMutex) { if (!core.getObjectIdODB().contains(objectId)) { core.getObjectIdODB().put(objectId, new ObjectId(objectId)); } else { System.err.println("Error: Generated objectId is already in objectIdODB?"); System.err.println("Trying again..."); continue; } if (objectList.containsKey(objectId)) { System.err.println("Error: Generated objectId is already in objectList?"); System.err.println("Trying again..."); continue; } core.getReusableIdODB().put(objectId, new ObjectId(objectId)); reusableIds.add(objectId); iteratedReusedIds++; break; } } } return objectId; } public Vector<SWGObject> getItemsInContainerByStfName(CreatureObject creature, long containerId, String stfName) { Vector<SWGObject> itemList = new Vector<SWGObject>(); SWGObject container = getObject(containerId); container.viewChildren(creature, false, false, (item) -> { if (item.getStfName() == stfName) { itemList.add(item); } }); return itemList; } public void useObject(CreatureObject creature, final SWGObject object) { if (creature == null || object == null) { return; } String template = ((object.getAttachment("customServerTemplate") == null) ? object.getTemplate() : (object.getTemplate().split("shared_")[0] + "shared_" + ((String) object.getAttachment("customServerTemplate")) + ".iff")); String bl = object.getStringAttribute("bio_link"); if (bl != null) { if (!object.getContainer().getTemplate().contains("shared_character_inventory")) { creature.sendSystemMessage("@base_player:must_biolink_to_use_from_inventory", DisplayType.Screen); return; } if (!bl.contains("@obj_attr_n:bio_link_pending") && !bl.contains(creature.getCustomName())) { creature.sendSystemMessage("@base_player:not_linked_to_holder", DisplayType.Screen); return; } if (bl.contains("@obj_attr_n:bio_link_pending")) { creature.setAttachment("BioLinkItemCandidate", object.getObjectID()); SUIWindow window = core.suiService.createSUIWindow("Script.messageBox", creature, creature, 0); window.setProperty("bg.caption.lblTitle:Text", "@sui:bio_link_item_title"); window.setProperty("Prompt.lblPrompt:Text", "@sui:bio_link_item_prompt"); window.setProperty("btnCancel:visible", "True"); window.setProperty("btnOk:visible", "True"); window.setProperty("btnUpdate:visible", "False"); window.setProperty("btnCancel:Text", "@cancel"); window.setProperty("btnOk:Text", "@ui_radial:bio_link"); Vector<String> returnList = new Vector<String>(); returnList.add("List.lstList:SelectedRow"); window.addHandler(0, "", Trigger.TRIGGER_OK, returnList, new SUICallback() { @Override public void process(SWGObject owner, int eventType, Vector<String> returnList) { ((CreatureObject) owner).sendSystemMessage("@base_player:item_bio_linked", (byte) 1); object.setStringAttribute("bio_link", owner.getCustomName()); object.setAttachment("bio_link_PlayerID", owner.getObjectID()); return; } }); window.addHandler(1, "", Trigger.TRIGGER_CANCEL, returnList, new SUICallback() { @Override public void process(SWGObject owner, int eventType, Vector<String> returnList) { return; } }); core.suiService.openSUIWindow(window); return; } } // Check if used item was a PUP String powerUpTemplate1 = "object/tangible/powerup/base/shared_armor_base.iff"; String powerUpTemplate2 = "object/tangible/powerup/base/shared_base.iff"; String powerUpTemplate3 = "object/tangible/powerup/base/shared_weapon_base.iff"; if (object.getTemplate().equals(powerUpTemplate1)) { // chestplate String effectName = (String) object.getAttachment("effectName"); int powerValue = (int) object.getAttachment("powerValue"); Long chestID = (Long) creature.getAttachment("EquippedChest"); if (chestID == null) return; TangibleObject chest = (TangibleObject) core.objectService.getObject(chestID); //chest.setIntAttribute(effectName, powerValue); chest.setAttachment("PUPEffectName", effectName); chest.setAttachment("PUPEffectValue", powerValue); } if (object.getTemplate().equals(powerUpTemplate2)) { // Shirt String effectName = (String) object.getAttachment("effectName"); int powerValue = (int) object.getAttachment("powerValue"); Long shirtID = (Long) creature.getAttachment("EquippedShirt"); if (shirtID == null) return; TangibleObject shirt = (TangibleObject) core.objectService.getObject(shirtID); //shirt.setIntAttribute(effectName, powerValue); shirt.setAttachment("PUPEffectName", effectName); shirt.setAttachment("PUPEffectValue", powerValue); } if (object.getTemplate().equals(powerUpTemplate3)) { // weapon SWGObject usedObject = null; if (object.getAttachment("UsedObjectID") != null) { long usedObjectid = (long) object.getAttachment("UsedObjectID"); usedObject = core.objectService.getObject(usedObjectid); } creature.setAttachment("LastUsedPUP", object.getObjectID()); if (usedObject == null) { Long weaponID = (Long) creature.getAttachment("EquippedWeapon"); System.out.println("weaponID " + weaponID); if (weaponID == null) return; WeaponObject weapon = (WeaponObject) core.objectService.getObject(weaponID); usedObject = (SWGObject) weapon; } core.buffService.addBuffToCreature(creature, "powerup_weapon", creature); int amount = object.getIntAttribute("num_in_stack"); if (amount == 1) destroyObject(object.getObjectID()); else object.setIntAttribute("num_in_stack", amount - 1); } creature.setUseTarget(object); int reuse_time; try { reuse_time = object.getIntAttribute("reuse_time"); } catch (NumberFormatException e) { reuse_time = 0; } try { DatatableVisitor visitor = ClientFileManager.loadFile("datatables/timer/template_command_mapping.iff", DatatableVisitor.class); boolean foundTemplate = false; for (int i = 0; i < visitor.getRowCount(); i++) { if (visitor.getObject(i, 0) != null && ((String) (visitor.getObject(i, 0))).equalsIgnoreCase(object.getTemplate())) { String commandName = (String) visitor.getObject(i, 1); String cooldownGroup = (String) visitor.getObject(i, 2); String animation = (String) visitor.getObject(i, 3); if (commandName.length() > 0) { BaseSWGCommand command = core.commandService.getCommandByName(commandName); if (command instanceof CombatCommand && animation.length() > 0) { ((CombatCommand) command).setDefaultAnimations(new String[] { animation }); } if (core.commandService.callCommand(creature, object, command, 0, "")) { core.commandService.removeCommand(creature, 0, command); return; } } else if (cooldownGroup.length() > 0) { if (creature.hasCooldown(cooldownGroup)) { return; } creature.addCooldown(cooldownGroup, reuse_time); } foundTemplate = true; break; } } if (!foundTemplate && reuse_time > 0) { if (creature.hasCooldown(template)) { return; } creature.addCooldown(template, reuse_time); } } catch (Exception e) { e.printStackTrace(); } if (object instanceof TangibleObject) { TangibleObject item = (TangibleObject) object; int uses = item.getUses(); if (uses > 0) { item.setUses(uses - 1); if (item.getUses() == 0) { destroyObject(object); } } } if (object.getStringAttribute("proc_name") != null) { String buffName = object.getStringAttribute("proc_name").replace("@ui_buff:", ""); if (object.getAttachment("alternateBuffName") != null) buffName = (String) object.getAttachment("alternateBuffName"); core.buffService.addBuffToCreature(creature, buffName, creature); } String filePath = "scripts/" + template.split("shared_", 2)[0].replace("shared_", "") + template.split("shared_", 2)[1].replace(".iff", "") + ".py"; if (FileUtilities.doesFileExist(filePath)) { filePath = "scripts/" + template.split("shared_", 2)[0].replace("shared_", ""); String fileName = template.split("shared_", 2)[1].replace(".iff", ""); PyObject method1 = core.scriptService.getMethod( "scripts/" + template.split("shared_", 2)[0].replace("shared_", ""), template.split("shared_", 2)[1].replace(".iff", ""), "use"); PyObject method2 = core.scriptService.getMethod( "scripts/" + template.split("shared_", 2)[0].replace("shared_", ""), template.split("shared_", 2)[1].replace(".iff", ""), "useObject"); if (method1 != null && method1.isCallable()) { method1.__call__(Py.java2py(core), Py.java2py(creature), Py.java2py(object)); } else if (method2 != null && method2.isCallable()) { method2.__call__(Py.java2py(core), Py.java2py(creature), Py.java2py(object)); } } } public void insertTimedEventBindings(ScheduledExecutorService executor) { } public void insertOpcodes(Map<Integer, INetworkRemoteEvent> swgOpcodes, Map<Integer, INetworkRemoteEvent> objControllerOpcodes) { swgOpcodes.put(Opcodes.SelectCharacter, new INetworkRemoteEvent() { @Override public void handlePacket(IoSession session, IoBuffer data) throws Exception { data = data.order(ByteOrder.LITTLE_ENDIAN); data.position(0); SelectCharacter selectCharacter = new SelectCharacter(); selectCharacter.deserialize(data); long objectId = selectCharacter.getCharacterId(); Client client = core.getClient(session); if (client == null) { System.err.println("NULL Client"); return; } CreatureObject creature = null; if (objectId != 0L && getObject(objectId) == null) { creature = getCreatureFromDB(objectId); if (creature == null) { System.err.println("Cant get creature from db"); } else { if (creature.getCustomName() == null || creature.getCustomName().isEmpty()) { System.err.println("Name: " + creature.getCustomName()); System.err.println("Player with ObjID of " + creature.getObjectID() + " tried logging in but has a null/empty name!"); return; } else { //System.err.println("SelectCharacter: not in object list"); Because it wasnt added still at this point } } } else { if (!(getObject(objectId) instanceof CreatureObject)) { System.out.println("Character is not an instance of CreatureObject or is null!"); return; } creature = (CreatureObject) getObject(objectId); if (creature.getCustomName() == null || creature.getCustomName().isEmpty()) { System.err.println( "Creature's custom name was null/empty! Name: " + creature.getCustomName()); } if (creature.getAttachment("disconnectTask") != null) ((ScheduledFuture<?>) creature.getAttachment("disconnectTask")).cancel(true); if (creature.getClient() != null) { if (!creature.getClient().getSession().isClosing()) { System.err.println("Character is already disconnecting..."); return; } creature.setClient(null); } } creature.setIntendedTarget(0); creature.setLookAtTarget(0); PlayerObject ghost = (PlayerObject) creature.getSlottedObject("ghost"); if (ghost == null) { System.err.println("The Character's Ghost is null!"); return; } System.out.println("Character '" + creature.getCustomName() + "' now zoning..."); ghost.clearFlagBitmask(PlayerFlags.LD); final CreatureObject finalCreature = creature; creature.viewChildren(creature, true, false, new Traverser() { public void process(SWGObject object) { finalCreature.makeUnaware(object); } }); creature.getAwareObjects().removeAll(creature.getAwareObjects()); creature.setAttachment("disconnectTask", null); creature.setClient(client); Planet planet = core.terrainService.getPlanetByID(creature.getPlanetId()); creature.setPlanet(planet); client.setParent(creature); session.setAttribute("CmdSceneReady", false); objectList.put(creature.getObjectID(), creature); creature.viewChildren(creature, true, true, (object) -> { objectList.put(object.getObjectID(), object); }); creature.viewChildren(creature, true, true, (object) -> { if (object != null) { if (object.getMutex() == null) object.initializeBaselines(); object.initAfterDBLoad(); if (object.getParentId() != 0 && object.getContainer() == null) object.setParent(getObject(object.getParentId())); object.getContainerInfo(object.getTemplate()); // if(getObject(object.getObjectID()) != null) // objectList.put(object.getObjectID(), object); if (!checkIfObjectAlreadyInList(object.getObjectID())) objectList.put(object.getObjectID(), object); } else { Thread.currentThread().dumpStack(); } }); if (creature.getParentId() != 0) { SWGObject parent = getObject(creature.getParentId()); if (parent == null) System.out.println("parentId isn't 0 but getObject(parentId) is null in SelectCharacter"); else if (parent.getContainer() == null) System.out.println("parent.getContainer() is null in SelectCharacter"); else if (parent.getContainer().getTemplate() == null) System.out.println("parent.getContainer().getTemplate() is null in SelectCharacter"); if (parent != null && parent.getContainer() != null && parent.getContainer().getTemplate() != null) System.out.println("Building: " + parent.getContainer().getTemplate()); parent._add(creature); } Point3D position = creature.getPosition(); if (Float.isNaN(position.x) || Float.isNaN(position.y) || Float.isNaN(position.z)) { creature.setPosition(new Point3D(0, 0, 0)); position = creature.getPosition(); } HeartBeatMessage heartBeat = new HeartBeatMessage(); session.write(heartBeat.serialize()); UnkByteFlag unkByteFlag = new UnkByteFlag(); session.write(unkByteFlag.serialize()); core.buffService.clearBuffs(creature); CmdStartScene startScene = new CmdStartScene((byte) 0, objectId, creature.getPlanet().getPath(), creature.getTemplate(), position.x, position.y, position.z, core.getGalacticTime() / 1000, 0); session.write(startScene.serialize()); ChatServerStatus chatServerStatus = new ChatServerStatus(); client.getSession().write(chatServerStatus.serialize()); VoiceChatStatus voiceStatus = new VoiceChatStatus(); client.getSession().write(voiceStatus.serialize()); ParametersMessage parameters = new ParametersMessage(); session.write(parameters.serialize()); ChatOnConnectAvatar chatConnect = new ChatOnConnectAvatar(); creature.getClient().getSession().write(chatConnect.serialize()); creature.makeAware(core.guildService.getGuildObject()); core.chatService.loadMailHeaders(client); core.simulationService.handleZoneIn(client); creature.makeAware(creature); //ChatOnGetFriendsList friendsListMessage = new ChatOnGetFriendsList(ghost); //client.getSession().write(friendsListMessage.serialize()); if (ghost != null) { //ghost.clearFlagBitmask(PlayerFlags.LD); String objectShortName = creature.getCustomName().toLowerCase(); if (creature.getCustomName().contains(" ")) { String[] splitName = creature.getCustomName().toLowerCase().split(" "); objectShortName = splitName[0].toLowerCase(); } core.chatService.playerStatusChange(objectShortName, (byte) 1); if (!ghost.getFriendList().isEmpty()) { // Find out what friends are online/offline for (String friend : ghost.getFriendList()) { SWGObject friendObject = core.objectService.getObjectByFirstName(friend); if (friendObject != null && friendObject.isInQuadtree()) { ChatFriendsListUpdate onlineNotifyStatus = new ChatFriendsListUpdate(friend, (byte) 1); client.getSession().write(onlineNotifyStatus.serialize()); } else { ChatFriendsListUpdate onlineNotifyStatus = new ChatFriendsListUpdate(friend, (byte) 0); client.getSession().write(onlineNotifyStatus.serialize()); } } } List<Integer> joinedChannels = ghost.getJoinedChatChannels(); for (Integer roomId : joinedChannels) { ChatRoom room = core.chatService.getChatRoom(roomId); if (room != null) { core.chatService.joinChatRoom(objectShortName, roomId); } // work-around for any channels that may have been deleted, or only spawn on server startup, that were added to the joined channels else { ghost.removeChannel(roomId); } } } creature.sendSystemMessage(core.getMotd(), DisplayType.Chat); if (creature.getGuildId() != 0) { Guild guild = core.guildService.getGuildById(creature.getGuildId()); if (guild != null && guild.getMembers().containsKey(creature.getObjectID())) { core.guildService.sendGuildMotd(creature, guild); } } if (core.getBountiesODB().contains(creature.getObjectID())) core.missionService.getBountyMap().put(creature.getObjectID(), (BountyListItem) core.getBountiesODB().get(creature.getObjectID())); if (creature.getSlottedObject("datapad") != null) { creature.getSlottedObject("datapad").viewChildren(creature, true, false, new Traverser() { @Override public void process(SWGObject obj) { if (obj instanceof MissionObject) { MissionObject mission = (MissionObject) obj; if (mission.getMissionType().equals("bounty")) { ((BountyMissionObjective) mission.getObjective()).checkBountyActiveStatus(core); } } } }); } // New players that skip tutorial if (creature.getLevel() <= (short) 1) { core.playerService.grantLevel(creature, 5); TangibleObject inventory = (TangibleObject) creature.getSlottedObject("inventory"); if (inventory != null) inventory.add(core.objectService.createObject( "object/tangible/npe/shared_npe_uniform_box.iff", creature.getPlanet())); } core.playerService.postZoneIn(creature); } }); } public void shutdown() { } public void loadSnapshotObjects(Planet planet) { System.out.println("Loading client objects for: " + planet.getName()); WorldSnapshotVisitor visitor = planet.getSnapshotVisitor(); int counter = 0; for (SnapshotChunk chunk : visitor.getChunks()) { ++counter; // Since the ids are just ints, they append 0xFFFF86F9 to them // This is demonstated in the packet sent to the server when you /target client-spawned buildouts // This is done for buildouts; uncertain about snapshot objects so it's commented for now //long objectId = Delta.createBuffer(8).putInt(chunk.id).putInt(0xF986FFFF).flip().getLong(); // Not sure what extension they add to 4-byte-only snapshot objectIds. With buildouts they add 0xFFFF86F9. This is demonstated in the packet sent to the server when you /target client-spawned objects int objectId = chunk.id; SWGObject obj = createObject(visitor.getName(chunk.nameId), objectId, planet, new Point3D(chunk.xPosition, chunk.yPosition, chunk.zPosition), new Quaternion(chunk.orientationW, chunk.orientationX, chunk.orientationY, chunk.orientationZ), null, false, false); if (obj != null) { obj.setContainerPermissions(WorldPermissions.WORLD_PERMISSIONS); obj.setisInSnapshot(true); obj.setParentId(chunk.parentId); if (obj instanceof CellObject) { ((CellObject) obj).setCellNumber(chunk.cellNumber); obj.setContainerPermissions(WorldCellPermissions.WORLD_CELL_PERMISSIONS); } } //System.out.print("\rLoading Object [" + counter + "/" + visitor.getChunks().size() + "] : " + visitor.getName(chunk.nameId)); } visitor.dispose(); synchronized (objectList) { for (SWGObject obj : objectList.values()) { if (obj.getParentId() != 0 && getObject(obj.getParentId()) != null) { SWGObject parent = getObject(obj.getParentId()); parent.add(obj); } } } System.out.println("Finished loading client objects for: " + planet.getName()); } /** * Creates a child object and places it at a position and orientation offset from the parent object. * @param parent The parent Object. * @param template The template file of the child. * @param position The position as an offset to the parent object. * @param orientation The orientation as an offset to the parent object. */ @SuppressWarnings("unchecked") public SWGObject createChildObject(SWGObject parent, String template, Point3D position, Quaternion orientation, int cellNumber) { if (cellNumber == -1) { float radians = parent.getRadians(); Point3D parentPos = parent.getWorldPosition(); float x = (float) ((Math.cos(radians) * position.x) + (Math.sin(radians) * position.z)); float y = position.y + parentPos.y; float z = (float) ((Math.cos(radians) * position.z) - (Math.sin(radians) * position.x)); x += parentPos.x; z += parentPos.z; position = new Point3D(x, y, z); orientation = MathUtilities.rotateQuaternion(orientation, radians, new Point3D(0, 1, 0)); } SWGObject child = createObject(template, 0, parent.getPlanet(), position, orientation); child.setContainerPermissions(WorldPermissions.WORLD_PERMISSIONS); if (parent.getAttachment("childObjects") == null) parent.setAttachment("childObjects", new Vector<SWGObject>()); ((Vector<SWGObject>) parent.getAttachment("childObjects")).add(child); if (cellNumber != -1) child.setAttachment("cellNumber", cellNumber); //core.simulationService.add(child, x, z); return child; } public SWGObject createChildObject(SWGObject parent, String template, float x, float y, float z, float qy, float qw) { return createChildObject(parent, template, new Point3D(x, y, z), new Quaternion(qw, 0, qy, 0), -1); } public SWGObject createChildObject(SWGObject parent, String template, float x, float y, float z, float qy, float qw, int cellNumber) { return createChildObject(parent, template, new Point3D(x, y, z), new Quaternion(qw, 0, qy, 0), cellNumber); } public void loadBuildoutObjects(Planet planet) throws InstantiationException, IllegalAccessException { DatatableVisitor buildoutTable = ClientFileManager .loadFile("datatables/buildout/areas_" + planet.getName() + ".iff", DatatableVisitor.class); System.out.println("loadBuildoutObjects"); for (int i = 0; i < buildoutTable.getRowCount(); i++) { String areaName = (String) buildoutTable.getObject(i, 0); float x1 = (Float) buildoutTable.getObject(i, 1); float z1 = (Float) buildoutTable.getObject(i, 2); readBuildoutDatatable( ClientFileManager.loadFile("datatables/buildout/" + planet.getName() + "/" + areaName + ".iff", DatatableVisitor.class), planet, x1, z1); } addCellsToBuildings(); finalizeBuildings(); } public void readBuildoutDatatable(DatatableVisitor buildoutTable, Planet planet, float x1, float z1) throws InstantiationException, IllegalAccessException { CrcStringTableVisitor crcTable = ClientFileManager.loadFile("misc/object_template_crc_string_table.iff", CrcStringTableVisitor.class); String planetName = planet.getName(); Map<Long, Long> duplicate = new HashMap<Long, Long>(); for (int i = 0; i < buildoutTable.getRowCount(); i++) { String template; if (buildoutTable.getColumnCount() <= 11) template = crcTable.getTemplateString((Integer) buildoutTable.getObject(i, 0)); else template = crcTable.getTemplateString((Integer) buildoutTable.getObject(i, 3)); if (template != null) { float px, py, pz, qw, qx, qy, qz, radius; long objectId = 0, containerId = 0, objectId2 = 0, containerId2 = 0; int type = 0, cellIndex = 0, portalCRC; if (buildoutTable.getColumnCount() <= 11) { objectId2 = (((Integer) buildoutTable.getObject(i, 0) == 0) ? 0 : Delta.createBuffer(8).putInt((Integer) buildoutTable.getObject(i, 0)) .putInt(0xF986FFFF).flip().getLong()); cellIndex = (Integer) buildoutTable.getObject(i, 1); px = (Float) buildoutTable.getObject(i, 2); py = (Float) buildoutTable.getObject(i, 3); pz = (Float) buildoutTable.getObject(i, 4); qw = (Float) buildoutTable.getObject(i, 5); qx = (Float) buildoutTable.getObject(i, 6); qy = (Float) buildoutTable.getObject(i, 7); qz = (Float) buildoutTable.getObject(i, 8); radius = (Float) buildoutTable.getObject(i, 9); portalCRC = (Integer) buildoutTable.getObject(i, 10); } else { // Since the ids are just ints, they append 0xFFFF86F9 to them // This is demonstated in the packet sent to the server when you /target client-spawned objects objectId = (((Integer) buildoutTable.getObject(i, 0) == 0) ? 0 : Delta.createBuffer(8).putInt((Integer) buildoutTable.getObject(i, 0)) .putInt(0xF986FFFF).flip().getLong()); objectId2 = Long.valueOf((Integer) buildoutTable.getObjectByColumnNameAndIndex("objid", i)); containerId = (((Integer) buildoutTable.getObject(i, 1) == 0) ? 0 : Delta.createBuffer(8).putInt((Integer) buildoutTable.getObject(i, 1)) .putInt(0xF986FFFF).flip().getLong()); containerId2 = Long .valueOf((Integer) buildoutTable.getObjectByColumnNameAndIndex("container", i)); type = (Integer) buildoutTable.getObject(i, 2); cellIndex = (Integer) buildoutTable.getObject(i, 4); px = (Float) buildoutTable.getObject(i, 5); py = (Float) buildoutTable.getObject(i, 6); pz = (Float) buildoutTable.getObject(i, 7); qw = (Float) buildoutTable.getObject(i, 8); qx = (Float) buildoutTable.getObject(i, 9); qy = (Float) buildoutTable.getObject(i, 10); qz = (Float) buildoutTable.getObject(i, 11); radius = (Float) buildoutTable.getObject(i, 12); portalCRC = (Integer) buildoutTable.getObject(i, 13); } // Treeku - Refactored to work around duplicate objectIds // Required for instances/heroics which are duplicated ie. 10 times //if(!template.equals("object/cell/shared_cell.iff") && objectId != 0 && getObject(objectId) != null) { if (!template.equals("object/cell/shared_cell.iff") && objectId != 0 && checkIfObjectAlreadyInList(objectId)) { SWGObject object = getObject(objectId); // Same coordinates is a true duplicate if ((px + ((containerId == 0) ? 0 : x1)) == object.getPosition().x && py == object.getPosition().y && (pz + ((containerId == 0) ? 0 : z1)) == object.getPosition().z) { //System.out.println("Duplicate buildout object: " + template); continue; } } if (duplicate.containsKey(containerId)) { containerId = duplicate.get(containerId); } // TODO needs to a way to work for mustafar and kashyyyk which both have instances //if (objectId != 0 && getObject(objectId) != null && (planetName.contains("dungeon") || planetName.contains("adventure"))) { if (objectId != 0 && checkIfObjectAlreadyInList(objectId) && (planetName.contains("dungeon") || planetName.contains("adventure"))) { SWGObject container = getObject(containerId); float x = (px + ((container == null) ? x1 : container.getPosition().x)); float z = (pz + ((container == null) ? z1 : container.getPosition().z)); String key = "" + CRC.StringtoCRC(planet.getName()) + CRC.StringtoCRC(template) + type + containerId + cellIndex + x + py + z; long newObjectId = 0; if (core.getDuplicateIdODB().contains(key)) { newObjectId = ((DuplicateId) core.getDuplicateIdODB().get(key)).getObjectId(); } else { newObjectId = generateObjectID(); core.getDuplicateIdODB().put(key, new DuplicateId(key, newObjectId)); } duplicate.put(objectId, newObjectId); objectId = newObjectId; } List<Long> containers = new ArrayList<Long>(); SWGObject object; if (objectId != 0 && containerId == 0) { if (portalCRC != 0) { // Is building //if (core.getSWGObjectODB().contains(objectId) && !duplicate.containsValue(objectId)){ if (core.getSWGObjectODB().contains(objectId)) { if (buildoutDEBUG) System.err.println("core.getSWGObjectODB().contains(objectId)" + template + " " + Long.toHexString(objectId)); continue; } if (duplicate.containsValue(objectId)) { if (buildoutDEBUG) System.err.println("duplicate.containsValue(objectId)" + template + " " + Long.toHexString(objectId)); continue; } if (checkIfObjectAlreadyInList(objectId)) { if (buildoutDEBUG) System.err.println("checkIfObjectAlreadyInList(objectId) " + template + " " + Long.toHexString(objectId)); continue; } containers.add(objectId); object = createObject(template, objectId, planet, new Point3D(px + x1, py, pz + z1), new Quaternion(qw, qx, qy, qz), null, true, true); object.setAttachment("childObjects", null); // must use the objectListId to identify the building later with cellMap.get(containerId) buildingMap.put(objectId, ((BuildingObject) object)); //System.out.println("buildingMap put " + Long.toHexString(objectId)); /*if (!duplicate.containsValue(objectId)) { ((BuildingObject) object).createTransaction(core.getBuildingODB().getEnvironment()); core.getBuildingODB().put((BuildingObject) object, Long.class, BuildingObject.class, ((BuildingObject) object).getTransaction()); ((BuildingObject) object).getTransaction().commitSync(); }*/ } else { // building without portal, Seems to never happen object = createObject(template, 0, planet, new Point3D(px + x1, py, pz + z1), new Quaternion(qw, qx, qy, qz), null, false, true); } if (object == null) { //System.err.println("Buildout table contained an entry that can't be instantiated!"); continue; } object.setContainerPermissions(WorldPermissions.WORLD_PERMISSIONS); if (radius > 256) object.setAttachment("bigSpawnRange", new Boolean(true)); if (!duplicate.containsValue(objectId) && object instanceof BuildingObject && portalCRC != 0) { synchronized (persistentBuildings) { persistentBuildings.add((BuildingObject) object); } } } else if (containerId != 0) { object = createObject(template, 0, planet, new Point3D(px, py, pz), new Quaternion(qw, qx, qy, qz), null, false, true); if (containers.contains(containerId)) { object.setContainerPermissions(WorldPermissions.WORLD_PERMISSIONS); object.setisInSnapshot(false); //containers.add(objectId); // ?!?!?! } if (object instanceof CellObject && cellIndex != 0) { object.setContainerPermissions(WorldCellPermissions.WORLD_CELL_PERMISSIONS); ((CellObject) object).setCellNumber(cellIndex); List<CellObject> cellList = cellMap.get(containerId); //System.out.println("Cell containerId " + Long.toHexString(containerId)); if (cellList != null) { cellList.add(((CellObject) object)); cellMap.put(containerId, cellList); } else { cellList = new ArrayList<CellObject>(); cellList.add(((CellObject) object)); cellMap.put(containerId, cellList); } } // SWGObject parent = getObject(containerId); // // if(parent != null && object != null) { // if(parent instanceof BuildingObject && ((BuildingObject) parent).getCellByCellNumber(cellIndex) != null) // continue; // parent.add(object); // } } else { object = createObject(template, 0, planet, new Point3D(px + x1, py, pz + z1), new Quaternion(qw, qx, qy, qz), null, false, true); object.setContainerPermissions(WorldPermissions.WORLD_PERMISSIONS); } if (object != null && object instanceof TangibleObject && !(object instanceof CreatureObject)) { ((TangibleObject) object).setStaticObject(true); } //System.out.println("Spawning: " + template + " at: X:" + object.getPosition().x + " Y: " + object.getPosition().y + " Z: " + object.getPosition().z); if (object != null) object.setAttachment("isBuildout", new Boolean(true)); } } // for(BuildingObject building : persistentBuildings) { // building.setAttachment("buildoutBuilding", true); // core.getSWGObjectODB().put(building.getObjectID(), building); // destroyObject(building); // } } private void addCellsToBuildings() { Iterator it = null; synchronized (buildingMap) { it = buildingMap.entrySet().iterator(); } while (it.hasNext()) { Map.Entry pairs = (Map.Entry) it.next(); long buildingId = (long) pairs.getKey(); BuildingObject building = (BuildingObject) pairs.getValue(); //System.out.println("We have buildingId " +buildingId); List<CellObject> cellList = cellMap.get(buildingId); if (cellList != null) { if (buildoutDEBUG) System.out.println("We have " + cellList.size() + " cells"); for (CellObject cell : cellList) { building.add(cell); if (buildoutDEBUG) System.out .println("Building : " + building.getTemplate() + " cell " + cell.getCellNumber()); } } else { /*System.out.println("Cellist null");*/} it.remove(); } } private void finalizeBuildings() { synchronized (persistentBuildings) { for (BuildingObject building : persistentBuildings) { building.setAttachment("buildoutBuilding", true); core.simulationService.add(building, building.getPosition().x, building.getPosition().z); //core.getSWGObjectODB().put(building.getObjectID(), building); //destroyObject(building); } } } public void readBuildoutDatatableOLD(DatatableVisitor buildoutTable, Planet planet, float x1, float z1) throws InstantiationException, IllegalAccessException { CrcStringTableVisitor crcTable = ClientFileManager.loadFile("misc/object_template_crc_string_table.iff", CrcStringTableVisitor.class); List<BuildingObject> persistentBuildings = new ArrayList<BuildingObject>(); Map<Long, Long> duplicate = new HashMap<Long, Long>(); for (int i = 0; i < buildoutTable.getRowCount(); i++) { String template; if (buildoutTable.getColumnCount() <= 11) template = crcTable.getTemplateString((Integer) buildoutTable.getObject(i, 0)); else template = crcTable.getTemplateString((Integer) buildoutTable.getObject(i, 3)); if (template != null) { float px, py, pz, qw, qx, qy, qz, radius; long objectId = 0, containerId = 0; int type = 0, cellIndex = 0, portalCRC; if (buildoutTable.getColumnCount() <= 11) { cellIndex = (Integer) buildoutTable.getObject(i, 1); px = (Float) buildoutTable.getObject(i, 2); py = (Float) buildoutTable.getObject(i, 3); pz = (Float) buildoutTable.getObject(i, 4); qw = (Float) buildoutTable.getObject(i, 5); qx = (Float) buildoutTable.getObject(i, 6); qy = (Float) buildoutTable.getObject(i, 7); qz = (Float) buildoutTable.getObject(i, 8); radius = (Float) buildoutTable.getObject(i, 9); portalCRC = (Integer) buildoutTable.getObject(i, 10); } else { // Since the ids are just ints, they append 0xFFFF86F9 to them // This is demonstated in the packet sent to the server when you /target client-spawned objects objectId = (((Integer) buildoutTable.getObject(i, 0) == 0) ? 0 : Delta.createBuffer(8).putInt((Integer) buildoutTable.getObject(i, 0)) .putInt(0xF986FFFF).flip().getLong()); containerId = (((Integer) buildoutTable.getObject(i, 1) == 0) ? 0 : Delta.createBuffer(8).putInt((Integer) buildoutTable.getObject(i, 1)) .putInt(0xF986FFFF).flip().getLong()); type = (Integer) buildoutTable.getObject(i, 2); cellIndex = (Integer) buildoutTable.getObject(i, 4); px = (Float) buildoutTable.getObject(i, 5); py = (Float) buildoutTable.getObject(i, 6); pz = (Float) buildoutTable.getObject(i, 7); qw = (Float) buildoutTable.getObject(i, 8); qx = (Float) buildoutTable.getObject(i, 9); qy = (Float) buildoutTable.getObject(i, 10); qz = (Float) buildoutTable.getObject(i, 11); radius = (Float) buildoutTable.getObject(i, 12); portalCRC = (Integer) buildoutTable.getObject(i, 13); } // Treeku - Refactored to work around duplicate objectIds // Required for instances/heroics which are duplicated ie. 10 times //if(!template.equals("object/cell/shared_cell.iff") && objectId != 0 && getObject(objectId) != null) { if (!template.equals("object/cell/shared_cell.iff") && objectId != 0 && (checkIfObjectAlreadyInList(objectId))) { SWGObject object = getObject(objectId); // Same coordinates is a true duplicate if ((px + ((containerId == 0) ? 0 : x1)) == object.getPosition().x && py == object.getPosition().y && (pz + ((containerId == 0) ? 0 : z1)) == object.getPosition().z) { //System.out.println("Duplicate buildout object: " + template); continue; } } if (duplicate.containsKey(containerId)) { containerId = duplicate.get(containerId); } String planetName = planet.getName(); // TODO needs to a way to work for mustafar and kashyyyk which both have instances //if (objectId != 0 && getObject(objectId) != null && (planetName.contains("dungeon") || planetName.contains("adventure"))) { if (objectId != 0 && checkIfObjectAlreadyInList(objectId) && (planetName.contains("dungeon") || planetName.contains("adventure"))) { SWGObject container = getObject(containerId); float x = (px + ((container == null) ? x1 : container.getPosition().x)); float z = (pz + ((container == null) ? z1 : container.getPosition().z)); String key = "" + CRC.StringtoCRC(planet.getName()) + CRC.StringtoCRC(template) + type + containerId + cellIndex + x + py + z; long newObjectId = 0; if (core.getDuplicateIdODB().contains(key)) { newObjectId = ((DuplicateId) core.getDuplicateIdODB().get(key)).getObjectId(); } else { newObjectId = generateObjectID(); core.getDuplicateIdODB().put(key, new DuplicateId(key, newObjectId)); } duplicate.put(objectId, newObjectId); objectId = newObjectId; } List<Long> containers = new ArrayList<Long>(); SWGObject object; if (objectId != 0 && containerId == 0) { if (portalCRC != 0) { if (core.getSWGObjectODB().contains(objectId) && !duplicate.containsValue(objectId)) continue; containers.add(objectId); object = createObject(template, objectId, planet, new Point3D(px + x1, py, pz + z1), new Quaternion(qw, qx, qy, qz), null, true, true); object.setAttachment("childObjects", null); /*if (!duplicate.containsValue(objectId)) { ((BuildingObject) object).createTransaction(core.getBuildingODB().getEnvironment()); core.getBuildingODB().put((BuildingObject) object, Long.class, BuildingObject.class, ((BuildingObject) object).getTransaction()); ((BuildingObject) object).getTransaction().commitSync(); }*/ } else { object = createObject(template, 0, planet, new Point3D(px + x1, py, pz + z1), new Quaternion(qw, qx, qy, qz), null, false, true); } if (object == null) continue; object.setContainerPermissions(WorldPermissions.WORLD_PERMISSIONS); if (radius > 256) object.setAttachment("bigSpawnRange", new Boolean(true)); if (!duplicate.containsValue(objectId) && object instanceof BuildingObject && portalCRC != 0) persistentBuildings.add((BuildingObject) object); } else if (containerId != 0) { object = createObject(template, 0, planet, new Point3D(px, py, pz), new Quaternion(qw, qx, qy, qz), null, false, true); if (containers.contains(containerId)) { object.setContainerPermissions(WorldPermissions.WORLD_PERMISSIONS); object.setisInSnapshot(false); containers.add(objectId); } if (object instanceof CellObject && cellIndex != 0) { object.setContainerPermissions(WorldCellPermissions.WORLD_CELL_PERMISSIONS); ((CellObject) object).setCellNumber(cellIndex); } SWGObject parent = getObject(containerId); if (parent != null && object != null) { if (parent instanceof BuildingObject && ((BuildingObject) parent).getCellByCellNumber(cellIndex) != null) continue; parent.add(object); } } else { object = createObject(template, 0, planet, new Point3D(px + x1, py, pz + z1), new Quaternion(qw, qx, qy, qz), null, false, true); object.setContainerPermissions(WorldPermissions.WORLD_PERMISSIONS); } if (object != null && object instanceof TangibleObject && !(object instanceof CreatureObject)) { ((TangibleObject) object).setStaticObject(true); } //System.out.println("Spawning: " + template + " at: X:" + object.getPosition().x + " Y: " + object.getPosition().y + " Z: " + object.getPosition().z); if (object != null) object.setAttachment("isBuildout", new Boolean(true)); } } for (BuildingObject building : persistentBuildings) { building.setAttachment("buildoutBuilding", true); core.getSWGObjectODB().put(building.getObjectID(), building); destroyObject(building); } } public int objsInContainer(SWGObject owner, TangibleObject container) { if (owner == null) { Console.println("Owner null!"); } if (container == null) { Console.println("Container is null!"); } final AtomicInteger count = new AtomicInteger(); container.viewChildren(owner, false, false, new Traverser() { @Override public void process(SWGObject child) { count.getAndIncrement(); } }); return count.get(); } public void persistObject(long key, Object value, ObjectDatabase odb) { odb.put(key, value); } public void deletePersistentObject(long key, ObjectDatabase odb) { odb.remove(key); } public void addStackableItem(TangibleObject item, SWGObject container) { // Maybe even better placed inside SWGObject.add(), so whenever an item is added to a container // it will bechecked if it is stackable and if there is already a stack to add it to if (!item.isStackable()) container.add(item); final Vector<SWGObject> alikeItemsInContainer = new Vector<SWGObject>(); container.viewChildren(container, false, false, new Traverser() { @Override public void process(SWGObject obj) { if (obj.getTemplate().equals(item.getTemplate())) { // Check if items are Droid Motors or Wirings if (obj.getTemplate().equals("object/tangible/loot/npc_loot/shared_wiring_generic.iff")) { if (obj.getAttachment("reverse_engineering_name") != null) { if (obj.getAttachment("reverse_engineering_name") .equals(item.getAttachment("reverse_engineering_name"))) { alikeItemsInContainer.add(obj); } } } else if (obj.getTemplate() .equals("object/tangible/loot/npc_loot/shared_copper_battery_generic.iff")) { if (obj.getAttachment("reverse_engineering_name") != null) { if (obj.getAttachment("reverse_engineering_name") .equals(item.getAttachment("reverse_engineering_name"))) { alikeItemsInContainer.add(obj); } } } else { alikeItemsInContainer.add(obj); } } } }); if (alikeItemsInContainer.size() == 0) { container.add(item); return; } TangibleObject alikeItem = (TangibleObject) alikeItemsInContainer.get(0); int alikeUses = alikeItem.getUses(); int itemUses = item.getUses(); if (itemUses == 0) itemUses = 1; int newUses = alikeUses + itemUses; alikeItem.setUses(newUses); core.objectService.destroyObject(item.getObjectID()); } }