diff --git a/scripts/commands/placestructure.py b/scripts/commands/placestructure.py new file mode 100644 index 00000000..edddb24e --- /dev/null +++ b/scripts/commands/placestructure.py @@ -0,0 +1,26 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + cmdArgs = commandString.split(" ") + + deedId = long(cmdArgs[0]) + deed = core.objectService.getObject(deedId) + + positionX = float(cmdArgs[1]) + positionZ = float(cmdArgs[2]) + #positionY = core.terrainService.getHeight(actor.getPlanetId(), positionX, positionZ) + 2 + + rotation = float(cmdArgs[3]) + + + #structureTemplate = deed.getAttachment("structureTemplate") + + core.housingService.placeStructure(actor, deed, positionX, positionZ, rotation) + + #building = core.objectService.createObject(structureTemplate, actor.getPlanet(), positionX, positionZ, positionY); + #core.simulationService.add(building, building.getPosition().x, building.getPosition().z); + + return \ No newline at end of file diff --git a/scripts/houses/player_house_generic_small_style_01.py b/scripts/houses/player_house_generic_small_style_01.py new file mode 100644 index 00000000..95d9f2b4 --- /dev/null +++ b/scripts/houses/player_house_generic_small_style_01.py @@ -0,0 +1,14 @@ +import sys +from services.housing import HouseTemplate +from engine.resources.scene import Point3D + +def setup(core): + houseTemplate = HouseTemplate("object/tangible/deed/player_house_deed/shared_generic_house_small_deed.iff", "object/building/player/shared_player_house_generic_small_style_01.iff", 2) + + houseTemplate.addBuildingSign("object/tangible/sign/player/shared_house_address.iff", Point3D(1, 2, 3)) + houseTemplate.addPlaceablePlanet("tatooine") + houseTemplate.addPlaceablePlanet("corellia") + houseTemplate.addPlaceablePlanet("naboo") + + core.housingService.addHousingTemplate(houseTemplate) + return \ No newline at end of file diff --git a/scripts/object/building/player/player_house_generic_small_style_01.py b/scripts/object/building/player/player_house_generic_small_style_01.py index ccad8904..17c11b52 100644 --- a/scripts/object/building/player/player_house_generic_small_style_01.py +++ b/scripts/object/building/player/player_house_generic_small_style_01.py @@ -1,4 +1,9 @@ import sys def setup(core, object): + sign = core.objectService.createChildObject(object, 'object/tangible/sign/player/shared_house_address.iff', -7.39, 2.36, 2, -1, 0, -1) + print(sign) + object.setAttachment("structureSign", sign) + + core.objectService.createChildObject(object, 'object/tangible/terminal/shared_terminal_player_structure.iff', -5, 0.74, -1.81, 0.707107, -0.707107, 1) return \ No newline at end of file diff --git a/scripts/object/tangible/deed/player_house_deed/generic_house_small_deed.py b/scripts/object/tangible/deed/player_house_deed/generic_house_small_deed.py index ccad8904..e100519a 100644 --- a/scripts/object/tangible/deed/player_house_deed/generic_house_small_deed.py +++ b/scripts/object/tangible/deed/player_house_deed/generic_house_small_deed.py @@ -1,4 +1,8 @@ import sys def setup(core, object): + object.setAttachment('radial_filename', 'structureDeed'); + return + +def use(core, actor, object): return \ No newline at end of file diff --git a/scripts/radial/structureDeed.py b/scripts/radial/structureDeed.py new file mode 100644 index 00000000..0ddee9f3 --- /dev/null +++ b/scripts/radial/structureDeed.py @@ -0,0 +1,11 @@ +from resources.common import RadialOptions +import sys + +def createRadial(core, owner, target, radials): + return + +def handleSelection(core, owner, target, option): + if option == 21 and target: + core.housingService.enterStructureMode(owner, target) + return + \ No newline at end of file diff --git a/src/main/NGECore.java b/src/main/NGECore.java index 0762507f..050e213b 100644 --- a/src/main/NGECore.java +++ b/src/main/NGECore.java @@ -57,6 +57,7 @@ import services.DevService; import services.EntertainmentService; import services.EquipmentService; import services.GroupService; +import services.housing.HousingService; import services.InstanceService; import services.LoginService; import services.MissionService; @@ -175,6 +176,8 @@ public class NGECore { public ResourceService resourceService; public ConversationService conversationService; + + public HousingService housingService; // Login Server @@ -286,6 +289,7 @@ public class NGECore { entertainmentService = new EntertainmentService(this); devService = new DevService(this); conversationService = new ConversationService(this); + housingService = new HousingService(this); if (config.keyExists("JYTHONCONSOLE.PORT")) { int jythonPort = config.getInt("JYTHONCONSOLE.PORT"); @@ -449,6 +453,7 @@ public class NGECore { spawnService.loadLairGroups(); spawnService.loadSpawnAreas(); + housingService.loadHousingTemplates(); equipmentService.loadBonusSets(); retroService.run(); diff --git a/src/protocol/swg/EnterStructurePlacementModeMessage.java b/src/protocol/swg/EnterStructurePlacementModeMessage.java new file mode 100644 index 00000000..3f12cf0a --- /dev/null +++ b/src/protocol/swg/EnterStructurePlacementModeMessage.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2013 + * + * 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 . + * + * 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 protocol.swg; + +import java.nio.ByteOrder; + +import main.NGECore; + +import org.apache.mina.core.buffer.IoBuffer; + +import services.travel.TravelPoint; +import engine.resources.objects.SWGObject; + +@SuppressWarnings("unused") +public class EnterStructurePlacementModeMessage extends SWGMessage { + + private SWGObject deed; + private String structureTemplate; + + public EnterStructurePlacementModeMessage(SWGObject deed, String structureTemplate) { + this.deed = deed; + this.structureTemplate = structureTemplate; + } + + @Override + public void deserialize(IoBuffer data) { + + } + + @Override + public IoBuffer serialize() { + IoBuffer result = IoBuffer.allocate(16 + structureTemplate.length()).order(ByteOrder.LITTLE_ENDIAN); + + result.putShort((short) 3); + result.putInt(0xE8A54DC1); + + result.putLong(deed.getObjectID()); + + deed.setAttachment("structureTemplate", structureTemplate); + result.put(getAsciiString(structureTemplate)); + + return result.flip(); + } + +} \ No newline at end of file diff --git a/src/services/DevService.java b/src/services/DevService.java index 0cde2b83..fe8c6e21 100644 --- a/src/services/DevService.java +++ b/src/services/DevService.java @@ -84,6 +84,7 @@ public class DevService implements INetworkDispatch { suiOptions.put((long) 21, "Weapons"); suiOptions.put((long) 22, "Misc Items"); suiOptions.put((long) 23, "Jedi Items"); + //suiOptions.put((long) 120, "House Deeds"); suiOptions.put((long) 110, "Survey Devices"); break; case 3: // [Items] Weapons @@ -990,8 +991,12 @@ public class DevService implements INetworkDispatch { SurveyTool solarSurveyTool = (SurveyTool) core.objectService.createObject("object/tangible/survey_tool/shared_survey_tool_solar.iff", planet); solarSurveyTool.setCustomName("Solar Survey Device"); inventory.add(solarSurveyTool); + return; - break; + case 120: + SWGObject houseDeed = core.objectService.createObject("object/tangible/deed/player_house_deed/shared_generic_house_small_deed.iff", planet); + inventory.add(houseDeed); + return; } } }); diff --git a/src/services/housing/HouseTemplate.java b/src/services/housing/HouseTemplate.java new file mode 100644 index 00000000..aaba8d7e --- /dev/null +++ b/src/services/housing/HouseTemplate.java @@ -0,0 +1,55 @@ +package services.housing; + +import java.util.HashMap; +import java.util.Map; +import java.util.Vector; + +import engine.resources.scene.Point3D; + +public class HouseTemplate +{ + private String deedTemplate; + private String buildingTemplate; + private int lotCost; + private Vector placeablePlanets; + private Map buildingSigns; + + public HouseTemplate(String deedTemplate, String buildingTemplate, int lotCost) + { + this.deedTemplate = deedTemplate; + this.buildingTemplate = buildingTemplate; + this.lotCost = lotCost; + this.placeablePlanets = new Vector(); + this.buildingSigns = new HashMap(); + } + + public void addBuildingSign(String signTemplate, Point3D signPosition) + { + buildingSigns.put(signTemplate, signPosition); + } + public void addPlaceablePlanet(String planetName) + { + this.placeablePlanets.add(planetName); + } + + public String getDeedTemplate() + { + return this.deedTemplate; + } + public String getBuildingTemplate() + { + return this.buildingTemplate; + } + public Map getBuildingSigns() + { + return this.buildingSigns; + } + public Vector getPlaceablePlanets() + { + return this.placeablePlanets; + } + public int getLotCost() + { + return this.lotCost; + } +} diff --git a/src/services/housing/HousingService.java b/src/services/housing/HousingService.java new file mode 100644 index 00000000..bbeab9f9 --- /dev/null +++ b/src/services/housing/HousingService.java @@ -0,0 +1,166 @@ +/******************************************************************************* + * Copyright (c) 2013 + * + * 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 . + * + * 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.housing; + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Map; +import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; + +import com.sleepycat.persist.EntityCursor; + +import main.NGECore; +import protocol.swg.EnterStructurePlacementModeMessage; +import resources.objects.building.BuildingObject; +import resources.objects.creature.CreatureObject; +import resources.objects.player.PlayerObject; +import resources.objects.tangible.TangibleObject; +import services.chat.Mail; +import services.equipment.BonusSetTemplate; +import engine.resources.objects.SWGObject; +import engine.resources.scene.Point3D; +import engine.resources.scene.Quaternion; +import engine.resources.service.INetworkDispatch; +import engine.resources.service.INetworkRemoteEvent; + +public class HousingService implements INetworkDispatch { + + private NGECore core; + private Map housingTemplates = new ConcurrentHashMap(); + + public HousingService(NGECore core) { + this.core = core; + core.commandService.registerCommand("placestructure"); + core.commandService.registerCommand("movefurniture"); + core.commandService.registerCommand("rotatefurniture"); + } + + public void enterStructureMode(CreatureObject player, TangibleObject deed) + { + if(housingTemplates.containsKey(deed.getTemplate())) + { + HouseTemplate houseTemplate = housingTemplates.get(deed.getTemplate()); + EnterStructurePlacementModeMessage packet = new EnterStructurePlacementModeMessage(deed, houseTemplate.getBuildingTemplate()); + player.getClient().getSession().write(packet.serialize()); + } + } + + public void placeStructure(final CreatureObject actor, TangibleObject deed, float positionX, float positionZ, float rotation) + { + HouseTemplate houseTemplate = housingTemplates.get(deed.getTemplate()); + + int structureLotCost = houseTemplate.getLotCost(); + String structureTemplate = houseTemplate.getBuildingTemplate(); + + // Lot stuff + if(actor.getAttachment("structureLots") == null) actor.setAttachment("structureLots", 10); // Temporary until better + + int playerLots = (int) actor.getAttachment("structureLots"); + if(playerLots - structureLotCost < 0) + { + actor.sendSystemMessage("You do not have enough available lots to place this structure.", (byte) 0); // should probably load this from an stf + return; + } + actor.setAttachment("structureLots", playerLots - structureLotCost); + + // Calculate our orientation and height + Quaternion quaternion = new Quaternion(1, 0, 0, 0); + quaternion = resources.common.MathUtilities.rotateQuaternion(quaternion, (float)((Math.PI/2) * rotation), new Point3D(0, 1, 0)); + + float positionY = core.terrainService.getHeight(actor.getPlanetId(), positionX, positionZ) + 2f; + + // Create the building + BuildingObject building = (BuildingObject) core.objectService.createObject(structureTemplate, 0, actor.getPlanet(), new Point3D(positionX, positionY, positionZ), quaternion); + core.simulationService.add(building, building.getPosition().x, building.getPosition().z, true); + + // Name the sign + TangibleObject sign = (TangibleObject) building.getAttachment("structureSign"); + sign.setCustomName2(actor.getCustomName() + "'s House"); + //building.add(sign); + + core.objectService.destroyObject(deed); + + // Structure management + Vector admins = new Vector<>(); + admins.add(actor.getObjectID()); + + building.setAttachment("structureOwner", actor.getObjectID()); + building.setAttachment("structureAdmins", admins); + + // Save structure to DB + //building.createTransaction(core.getBuildingODB().getEnvironment()); + //core.getBuildingODB().put(building, Long.class, BuildingObject.class, building.getTransaction()); + //building.getTransaction().commitSync(); + } + + @SuppressWarnings("unchecked") + public boolean getPermissions(SWGObject player, SWGObject container) + { + if(((Vector) container.getContainer().getAttachment("structureAdmins")).contains(player.getObjectID())) return true; + return false; + } + + public void addHousingTemplate(HouseTemplate houseTemplate) + { + housingTemplates.put(houseTemplate.getDeedTemplate(), houseTemplate); + } + + public void loadHousingTemplates() { + Path p = Paths.get("scripts/houses/"); + FileVisitor fv = new SimpleFileVisitor() + { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException + { + System.out.println("Loading housing template " + file.getFileName()); + core.scriptService.callScript("scripts/houses/", file.getFileName().toString().replace(".py", ""), "setup", core); + return FileVisitResult.CONTINUE; + } + }; + try + { + Files.walkFileTree(p, fv); + } + catch (IOException e) { e.printStackTrace(); } + } + + + + @Override + public void insertOpcodes(Map arg0, + Map arg1) { + // TODO Auto-generated method stub + + } + + @Override + public void shutdown() { + + } +} \ No newline at end of file diff --git a/src/services/object/ObjectService.java b/src/services/object/ObjectService.java index cb85e06d..6c5a44a4 100644 --- a/src/services/object/ObjectService.java +++ b/src/services/object/ObjectService.java @@ -877,7 +877,7 @@ public class ObjectService implements INetworkDispatch { * @param position The position as an offset to the parent object. * @param orientation The orientation as an offset to the parent object. */ - public void createChildObject(SWGObject parent, String template, Point3D position, Quaternion orientation, int cellNumber) { + public SWGObject createChildObject(SWGObject parent, String template, Point3D position, Quaternion orientation, int cellNumber) { if(cellNumber == -1) { @@ -907,15 +907,15 @@ public class ObjectService implements INetworkDispatch { child.setAttachment("cellNumber", cellNumber); //core.simulationService.add(child, x, z); - + return child; } - public void createChildObject(SWGObject parent, String template, float x, float y, float z, float qy, float qw) { - 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) { + return createChildObject(parent, template, new Point3D(x, y, z), new Quaternion(qw, 0, qy, 0), -1); } - public void createChildObject(SWGObject parent, String template, float x, float y, float z, float qy, float qw, int cellNumber) { - createChildObject(parent, template, new Point3D(x, y, z), new Quaternion(qw, 0, qy, 0), cellNumber); + 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 {