// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.net.client.msg; import engine.Enum.*; import engine.gameManager.BuildingManager; import engine.gameManager.ZoneManager; import engine.math.Vector3fImmutable; import engine.net.AbstractConnection; import engine.net.ByteBufferReader; import engine.net.ByteBufferWriter; import engine.net.client.Protocol; import engine.objects.*; import org.joda.time.DateTime; import org.joda.time.Period; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * Open manage city asset window */ public class ManageCityAssetsMsg extends ClientNetMsg { //messageType //C->S 2: S->C: 0, 3, 4, 6 //C->S 15: S->C: 15 //C->S 14: S->C: 14 //C->S ?: S->C: 10, 11, 16 //C->S 2 = manage this asset // 20 = manage entire city //S->C, 0 = error message // 3 = manage asset // 4 = no access / building info public int actionType; public String assetName; public String CityName; public int upgradeCost; public byte labelProtected; public byte labelSiege; public byte labelCeaseFire; public byte buttonTransfer; public byte buttonDestroy; public byte buttonAbandon; public byte buttonUpgrade; private int targetID; private int targetType; private int targetType1; private int targetType2; private int targetType3; private int targetID1; private int targetID2; private int targetID3; private String AssetName1; private int rank; private int symbol; private int unknown04; private int unknown05; private int unknown06; private int unknown07; private int unknown14; private int unknown15; private int unknown16; private int unknown17; private int unknown54; private int preName01; private byte UnkByte03; private byte UnkByte04; private int strongbox; private int baneHour; private PlayerCharacter assetManager; private Building asset; /** * This is the general purpose constructor */ public ManageCityAssetsMsg() { super(Protocol.MANAGECITYASSETS); this.actionType = 0; this.targetType = 0; this.targetID = 0; this.preName01 = 0; this.assetName = ""; this.CityName = ""; this.rank = 0; this.symbol = 0; this.unknown04 = 0; this.unknown06 = 0; this.unknown07 = 0; this.unknown14 = 0; this.unknown15 = 0; this.unknown16 = 0; this.unknown17 = 0; this.strongbox = 0; this.targetType1 = 0; this.targetType2 = 0; this.targetType3 = 0; this.targetID1 = 0; this.targetID2 = 0; this.targetID3 = 0; this.UnkByte03 = 0; this.UnkByte04 = 0; this.AssetName1 = ""; this.unknown54 = 0; this.strongbox = 0; this.upgradeCost = 0; this.labelProtected = 0; this.labelSiege = 0; this.labelCeaseFire = 0; this.buttonTransfer = 0; this.buttonDestroy = 0; this.buttonAbandon = 0; this.buttonUpgrade = 0; } public ManageCityAssetsMsg(PlayerCharacter pc, Building asset) { super(Protocol.MANAGECITYASSETS); this.assetManager = pc; this.asset = asset; } /** * This constructor is used by NetMsgFactory. It attempts to deserialize the ByteBuffer into a message. If a BufferUnderflow occurs (based on reading past the limit) then this constructor Throws that Exception to the caller. */ public ManageCityAssetsMsg(AbstractConnection origin, ByteBufferReader reader) { super(Protocol.MANAGECITYASSETS, origin, reader); } public int getTargetID() { return targetID; } public void setTargetID(int targetID) { this.targetID = targetID; } protected int getPowerOfTwoBufferSize() { return (20); // 2^10 == 1024 } public int getTargetType() { return targetType; } public void setTargetType(int targetType) { this.targetType = targetType; } public void setTargetType3(int targetType3) { this.targetType3 = targetType3; } public void setTargetID3(int targetID3) { this.targetID3 = targetID3; } /** * Deserializes the subclass specific items to the supplied NetMsgWriter. */ @Override protected void _deserialize(ByteBufferReader reader) { actionType = reader.getInt(); targetType = reader.getInt(); targetID = reader.getInt(); if (this.actionType == 20) { reader.getInt(); this.baneHour = reader.getInt(); reader.getInt(); reader.getInt(); reader.getInt(); reader.getInt(); reader.getInt(); } else if (this.actionType == 5) { //rename building. reader.getInt(); assetName = reader.getString(); for (int i = 0; i < 5; i++) reader.getInt(); } else if (this.actionType == 2) { reader.getInt(); this.strongbox = reader.getInt(); reader.getInt(); reader.getInt(); reader.getInt(); reader.getInt(); } else { for (int i = 0; i < 6; i++) reader.getInt(); } } /** * Serializes the subclass specific items from the supplied NetMsgReader. */ @Override protected void _serialize(ByteBufferWriter writer) { writer.putInt(this.actionType); if (this.actionType == 2) { writer.putInt(asset.getObjectType().ordinal()); writer.putInt(asset.getObjectUUID()); writer.putInt(0); writer.putInt(asset.reserve); writer.putInt(0); return; } if (this.actionType == 13) { writer.putInt(asset.getObjectType().ordinal()); writer.putInt(asset.getObjectUUID()); writer.putInt(0); writer.putInt(0); writer.putInt(asset.getHirelings().size()); for (AbstractCharacter hireling : asset.getHirelings().keySet()) { if (!hireling.getObjectType().equals(GameObjectType.NPC)) writer.putString(hireling.getName()); else { NPC npc = (NPC) hireling; if (!npc.getNameOverride().isEmpty()) { writer.putString(npc.getNameOverride()); } else if (npc.getContract() != null) { if (npc.getContract().isTrainer()) { writer.putString(npc.getName() + ", " + npc.getContract().getName()); } else { writer.putString(npc.getName() + " " + npc.getContract().getName()); } } else { writer.putString(npc.getName()); } } } writer.putInt(0); writer.putInt(0); writer.putInt(0); } //Bane window if (this.actionType == 11) { writer.putInt(asset.getObjectType().ordinal()); writer.putInt(asset.getObjectUUID()); for (int a = 0; a < 5; a++) writer.putInt(0); writer.putInt(asset.getHirelings().size()); for (AbstractCharacter npcHire : asset.getHirelings().keySet()) { writer.putInt(npcHire.getObjectType().ordinal()); writer.putInt(npcHire.getObjectUUID()); if (npcHire.getObjectType() == GameObjectType.NPC) writer.putString(((NPC) npcHire).getContract().getName()); else writer.putString("Guard Captain"); writer.putString(npcHire.getName()); writer.putInt(1); writer.putInt(0); if (npcHire.getObjectType() == GameObjectType.NPC) writer.putInt(((NPC) npcHire).getContract().getIconID()); // Was 60 else if (npcHire.getObjectType() == GameObjectType.Mob) { writer.putInt(((Mob) npcHire).getContract().getIconID()); // Was 60 } else writer.putInt(5); writer.put((byte) 0); writer.put((byte) 0); writer.put((byte) 1); writer.put((byte) 0); writer.put((byte) 0); } return; } if (this.actionType == 15) { writer.putInt(1); writer.putInt(1); City city = null; Zone playerZone = ZoneManager.findSmallestZone(assetManager.getLoc()); Set buildings = ZoneManager.findSmallestZone(assetManager.getLoc()).zoneBuildingSet; Building tol = null; if (playerZone.getPlayerCityUUID() != 0) city = City.GetCityFromCache(playerZone.getPlayerCityUUID()); if (city != null) tol = city.getTOL(); writer.putInt(0); // 1 + String = custom message, cant control assets. writer.putInt(0); writer.putInt(0); //array writer.putInt(buildings.size()); int i = 0; for (Building building : buildings) { i++; writer.putString(building.getName()); //ARRAY writer.putInt(building.getObjectType().ordinal()); //? writer.putInt(building.getObjectUUID()); //? writer.putInt(4); writer.putInt(4); writer.put((byte) 0); writer.put((byte) 0); writer.put((byte) 1); writer.put((byte) 1); //max distance to bypass clientside check. float maxDistance = 2000; writer.putFloat(maxDistance); writer.putInt(0); writer.putInt(0); writer.putInt(0); if (building.getPatrolPoints() != null) { writer.putInt(building.getPatrolPoints().size()); for (Vector3fImmutable patrolPoint : building.getPatrolPoints()) { writer.putVector3f(patrolPoint); } } else { writer.putInt(0); } writer.putInt(0); //Sentry Point if (building.getBlueprint() != null && building.getBlueprint().getBuildingGroup() == BuildingGroup.BARRACK) { writer.putInt(1); //Tab left Random Town? //Opens up 16 Bytes writer.putInt(4); writer.putInt(0); writer.putInt(0); writer.putInt(4); } else writer.putInt(0); writer.putInt(0); //array with size 32 bytes. // Adds information of building } writer.putInt(0); //ARRAY writer.putInt(0); } if (this.actionType == 18) { Zone zone = asset.getParentZone(); if (zone == null) return; City banedCity = City.getCity(zone.getPlayerCityUUID()); if (banedCity == null) return; Bane bane = banedCity.getBane(); if (bane == null) return; Guild attackerGuild = bane.getOwner().getGuild(); if (attackerGuild == null) return; writer.putInt(asset.getObjectType().ordinal()); writer.putInt(asset.getObjectUUID()); writer.putInt(0); writer.putString(attackerGuild.getName()); writer.putString(Guild.GetGL(attackerGuild).getName()); writer.putInt(bane.getSiegePhase().ordinal()); //1 challenge //2 standoff //3 war writer.put((byte) 0); //if (!bane.isAccepted() && this.assetManager.getGuild() == banedCity.getGuild() && GuildStatusController.isInnerCouncil(this.assetManager.getGuildStatus())) // writer.put((byte) 1); //canSetTime //else writer.put((byte) 0); DateTime placedOn = bane.getLiveDate(); if (placedOn == null) placedOn = new DateTime(DateTime.now()); //set Calander to date of bane live. DateTime now = DateTime.now(); DateTime defaultTime = new DateTime(bane.getPlacementDate()); DateTime playerEnterWorldTime = new DateTime(this.assetManager.getTimeStamp("EnterWorld")); Period period = new Period(playerEnterWorldTime.getMillis(), now.getMillis()); int hoursLoggedIn = period.getHours(); hoursLoggedIn = hoursLoggedIn < 0 ? 0 : hoursLoggedIn; defaultTime = defaultTime.plusDays(2); defaultTime = defaultTime.hourOfDay().setCopy(22); defaultTime = defaultTime.minuteOfHour().setCopy(0); defaultTime = defaultTime.secondOfMinute().setCopy(0); long curTime = now.getMillis(); long timeLeft = 0; if (bane.getLiveDate() != null) timeLeft = bane.getLiveDate().getMillis() - curTime; else timeLeft = defaultTime.getMillis() - curTime + 1000; //DO not touch these. They are static formula's until i get the correct converter for SB Time. writer.put((byte) placedOn.dayOfMonth().get()); writer.put((byte) placedOn.monthOfYear().get()); writer.putInt(placedOn.year().get() - 1900); writer.put((byte) 0); writer.put((byte) 0); writer.put((byte) 0); if (timeLeft < 0) writer.putInt(0); else writer.putInt((int) timeLeft / 1000); // Time remaing until bane/Seconds if (attackerGuild.getGuildState() == GuildState.Sworn) writer.putInt(4); //3 capture/errant,4 capture/sworn, 5 destroy/soveirgn. else writer.putInt(5); writer.put((byte) (16 - hoursLoggedIn)); // hour start writer.put((byte) (24 - hoursLoggedIn)); // hour end writer.put((byte) 2); writer.putString(banedCity.getCityName()); writer.putString(Guild.GetGL(bane.getOwner().getGuild()) != null ? Guild.GetGL(bane.getOwner().getGuild()).getName() : "No Guild Leader"); GuildTag._serializeForDisplay(attackerGuild.getGuildTag(), writer); GuildTag._serializeForDisplay(attackerGuild.getNation().getGuildTag(), writer); writer.putInt(0); writer.putInt(0); writer.putInt(0); writer.putInt(0); writer.putInt(0); } if (this.actionType == 3) { writer.putInt(targetType); writer.putInt(targetID); Guild nation = null; Building building = BuildingManager.getBuildingFromCache(targetID); Guild guild = building.getGuild(); Zone zone = ZoneManager.findSmallestZone(building.getLoc()); writer.putInt(0);//unknown Might be to allow manager to open or not! writer.putString(building.getName()); AbstractCharacter buildingOwner = building.getOwner(); if (buildingOwner == null) writer.putString("Morloch"); else writer.putString(buildingOwner.getName()); if (zone == null) writer.putString("Forlord"); else writer.putString(zone.getName()); writer.putString(building.getGuild().getName()); writer.putInt(building.getRank()); writer.putInt(1); // Gold only writer.putInt(2308551); //Gold if (building.getBlueprint() == null) writer.putInt(0); else writer.putInt(building.getBlueprint().getMaintCost()); // maint cost LocalDateTime maintDate = building.maintDateTime; if (maintDate == null) maintDate = LocalDateTime.now(); writer.putLocalDateTime(maintDate); // current time // utc offset? writer.putInt((int) java.time.Duration.between(LocalDateTime.now(), maintDate).getSeconds()); // Seconds to maint date writer.putInt(building.getStrongboxValue()); writer.putInt(building.reserve);//reserve Sets the buildings reserve display writer.putInt(0);//prosperity under maintenance (wtf is prosperity?) writer.putInt(10); writer.putFloat((float) .1); if (this.buttonUpgrade == 1) { if (building.getBlueprint() == null) this.upgradeCost = Integer.MAX_VALUE; else if (building.getRank() == building.getBlueprint().getMaxRank()) this.upgradeCost = Integer.MAX_VALUE; else this.upgradeCost = building.getBlueprint().getRankCost(Math.min(building.getRank() + 1, 7)); writer.putInt(this.upgradeCost); } else writer.putInt(0); LocalDateTime uc = LocalDateTime.now(); if (building.getDateToUpgrade() != null) uc = building.getDateToUpgrade(); long timeLeft = uc.atZone(ZoneId.systemDefault()) .toInstant().toEpochMilli() - System.currentTimeMillis(); long hour = timeLeft / 3600000; long noHour = timeLeft - (hour * 3600000); long minute = noHour / 60000; long noMinute = noHour - (minute * 60000); long second = noMinute / 1000; writer.put((byte) 0);//Has to do with repair time. A 1 here puts 23.9 hours in repair time A 2 here is 1.9 days writer.put((byte) 0);//unknown writer.putInt(0); //unknown if (LocalDateTime.now().isAfter(uc)) { writer.put((byte) 0); writer.put((byte) 0); writer.put((byte) 0); } else { writer.put((byte) (hour)); writer.put((byte) minute); writer.put((byte) second); } if (timeLeft < 0) writer.putInt(0); else writer.putInt((int) timeLeft); writer.putInt((int) building.getCurrentHitpoints()); writer.putInt((int) building.getMaxHitPoints()); writer.putInt(BuildingManager.GetRepairCost(building));//sets the repair cost. writer.putInt(0);//unknown if (building.getBlueprint() == null) writer.putInt(0); else writer.putInt(building.getBlueprint().getSlotsForRank(building.getRank())); writer.put((byte) 1);//Has to do with removing update timer and putting in cost for upgrade writer.put(labelProtected); // 1 sets protection to invulnerable. writer.put(labelSiege);// 1 sets the protection under siege writer.put(labelCeaseFire); //0 with 1 set above sets to under siege // 1 with 1 set above sets protection status to under siege(cease fire) writer.put(buttonTransfer);// 1 enables the transfer asset button writer.put(buttonDestroy);// 1 enables the destroy asset button writer.put(buttonAbandon);// 1 here enables the abandon asset button writer.put(buttonUpgrade); //disable upgrade building if (building.getBlueprint() == null) writer.putInt(0); else writer.putInt(building.getBlueprint().getIcon()); //Symbol if (guild == null) { for (int i = 0; i < 3; i++) writer.putInt(16); for (int i = 0; i < 2; i++) writer.putInt(0); } else { GuildTag._serializeForDisplay(guild.getGuildTag(), writer); nation = guild.getNation(); } if (nation == null) { for (int i = 0; i < 3; i++) writer.putInt(16); for (int i = 0; i < 2; i++) writer.putInt(0); } else { GuildTag._serializeForDisplay(nation.getGuildTag(), writer); } writer.putInt(0); writer.putInt(0); writer.putInt(0);//1 makes it so manage window does not open. if (!building.assetIsProtected() && !building.getProtectionState().equals(ProtectionState.PENDING)) { writer.putInt(0); } else { writer.putInt(1); //kos on/off? writer.putInt(3); // was 3 if (zone.getPlayerCityUUID() != 0 && asset.assetIsProtected()) { writer.putInt(GameObjectType.Building.ordinal()); writer.putInt(City.getCity(zone.getPlayerCityUUID()).getTOL().getObjectUUID()); } else { writer.putInt(0); writer.putInt(0); } writer.putInt(0); writer.putInt(0); writer.putInt(targetType3); writer.putInt(targetID3); if (building.getProtectionState() == ProtectionState.PENDING) writer.put((byte) 1); //Accept or decline. else writer.put((byte) 0); if (building.taxType == TaxType.NONE) writer.put((byte) 0); //? ?? else if (building.taxDateTime != null) writer.put((byte) 1); else writer.put((byte) 0); writer.putString(""); //tree of life protection tax writer.putInt(0); //?? writer.putInt(0); //?? if (building.taxType == TaxType.NONE) { writer.putInt(0); writer.putInt(0); } else if (building.taxType == TaxType.WEEKLY) { writer.putInt(building.taxAmount); writer.putInt(0); } else { writer.putInt(0); writer.putInt(building.taxAmount); } writer.put(building.enforceKOS ? (byte) 1 : 0); //enforceKOS writer.put((byte) 0); //? writer.putInt(1); } ConcurrentHashMap npcList = building.getHirelings(); writer.putInt(npcList.size()); if (npcList.size() > 0) { for (AbstractCharacter npcHire : npcList.keySet()) { writer.putInt(npcHire.getObjectType().ordinal()); if (npcHire.getObjectType() == GameObjectType.Mob) writer.putInt(((Mob) npcHire).getDBID()); else writer.putInt(npcHire.getObjectUUID()); if (npcHire.getObjectType() == GameObjectType.NPC) { writer.putString(((NPC) npcHire).getContract().getName()); writer.putString(npcHire.getName()); } else if (npcHire.getObjectType() == GameObjectType.Mob) { writer.putString(((Mob) npcHire).getContract().getName()); if (((Mob) npcHire).getNameOverride().length() > 0) { writer.putString(((Mob) npcHire).getNameOverride()); } else { writer.putString(npcHire.getName()); } } else writer.putString("Error: Nothing Here"); writer.putInt(npcHire.getRank()); writer.putInt(Blueprint.getNpcMaintCost(npcHire.getRank())); if (npcHire.getObjectType() == GameObjectType.NPC) writer.putInt(((NPC) npcHire).getContract().getIconID()); // Was 60 else if (npcHire.getObjectType() == GameObjectType.Mob) writer.putInt(((Mob) npcHire).getContract().getIconID()); // Was 60 int contractID = 0; if (npcHire.getObjectType() == GameObjectType.Mob) contractID = ((Mob) npcHire).getContract().getContractID(); else if (npcHire.getObjectType() == GameObjectType.NPC) contractID = ((NPC) npcHire).getContract().getContractID(); if (contractID == 830) { writer.putInt(24580); } else if (building.getBlueprint() != null && (building.getBlueprint().getBuildingGroup() == BuildingGroup.FORGE || building.getBlueprint().getBuildingGroup() == BuildingGroup.MAGICSHOP || building.getBlueprint().getBuildingGroup() == BuildingGroup.TAILOR)) { writer.put((byte) 0); writer.put((byte) 4); writer.put((byte) 128); writer.put((byte) 0); } else { writer.put((byte) 0); if (building.getBlueprint() != null && building.getBlueprint().getBuildingGroup() == BuildingGroup.BARRACK) writer.put((byte) 1); else writer.put((byte) 0); writer.put((byte) 0); writer.put((byte) 0); } if (!npcHire.isAlive()) { writer.put((byte) 1); // 1 SHOWs respawning int respawnRemaining = (int) (((Mob) npcHire).deathTime + ((Mob) npcHire).spawnTime * 1000 - System.currentTimeMillis()) / 1000; writer.putInt(respawnRemaining); // Seconds in respawn remaining. writer.putInt(((Mob) npcHire).spawnTime); // max seconds for respawn } else writer.put((byte) 0); } } } if (this.actionType == 4) { writer.putInt(targetType); writer.putInt(targetID); Building building = BuildingManager.getBuildingFromCache(targetID); writer.putInt(preName01); writer.putString(building.getName()); //assetName writer.putString(building.getOwnerName()); //ownerName writer.putString(building.getGuild().getName());//guild name writer.putString(building.getCityName()); //City Name writer.putInt(building.getRank()); if (building.getBlueprint() == null) writer.putInt(0); else writer.putInt(building.getBlueprint().getIcon()); //tags GuildTag._serializeForDisplay(building.getGuild().getGuildTag(), writer); GuildTag._serializeForDisplay(building.getGuild().getNation().getGuildTag(), writer); writer.putInt(unknown14); writer.putInt(unknown15); writer.putInt(unknown16); writer.putInt(unknown17); writer.putInt(0); // previously uninitialized unknown18 } } public int getRank() { return rank; } public void setRank(int rank) { this.rank = rank; } public int getSymbol() { return symbol; } public void setSymbol(int symbol) { this.symbol = symbol; } public int getUnknown04() { return unknown04; } public void setUnknown04(int unknown04) { this.unknown04 = unknown04; } public int getUnknown05() { return unknown05; } public void setUnknown05(int unknown05) { this.unknown05 = unknown05; } public int getUnknown06() { return unknown06; } public void setUnknown06(int unknown06) { this.unknown06 = unknown06; } public void setUnknown07(int unknown07) { this.unknown07 = unknown07; } public String getAssetName() { return assetName; } public void setAssetName(String AssetName) { this.assetName = AssetName; } public void setAssetName1(String AssetName1) { this.AssetName1 = AssetName1; } public String getCityName() { return CityName; } public void setUnknown54(int unknown54) { this.unknown54 = unknown54; } public int getStrongbox() { return strongbox; } public void setStrongbox(int strongbox) { this.strongbox = strongbox; } public int getBaneHour() { return baneHour; } public Building getAsset() { return asset; } public void setAsset(Building asset) { this.asset = asset; } } //Debug Info //Run: Failed to make object TEMPLATE:135700 INSTANCE:1717987027141... (t=50.46) (r=7/4/2011 11:56:39) //C:\ArcanePrime\Main_Branch\Shadowbane\Source\ArcObjectLoader.cpp(466):ERROR: ArcObjectLoader::Run: Failed to make object TEMPLATE:108760 INSTANCE:1717987027161... (t=50.46) (r=7/4/2011 11:56:39) //C:\ArcanePrime\Main_Branch\Shadowbane\Source\ArcObjectLoader.cpp(466):ERROR: ArcObjectLoader::Run: Failed to make object TEMPLATE:108760 INSTANCE:1717987027177... (t=50.67) (r=7/4/2011 11:56:39) //C:\ArcanePrime\Main_Branch\Shadowbane\Source\ArcObjectLoader.cpp(466):ERROR: ArcObjectLoader::Run: Failed to make object TEMPLATE:60040 INSTANCE:1717987027344... (t=50.87) (r=7/4/2011 11:56:39) //C:\ArcanePrime\Main_Branch\Shadowbane\Source\ArcObjectLoader.cpp(466):ERROR: ArcObjectLoader::Run: Failed to make object TEMPLATE:3 INSTANCE:1717987027164... (t=50.88) (r=7/4/2011 11:56:39)