// when a painting is placed... @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPaintingPlace(PaintingPlaceEvent event) { // FEATURE: similar to above, placing a painting requires build permission in the claim // if the player doesn't have permission, don't allow the placement String noBuildReason = GriefPrevention.instance.allowBuild(event.getPlayer(), event.getPainting().getLocation()); if (noBuildReason != null) { event.setCancelled(true); GriefPrevention.sendMessage(event.getPlayer(), TextMode.Err, noBuildReason); return; } // otherwise, apply entity-count limitations for creative worlds else if (GriefPrevention.instance.creativeRulesApply(event.getPainting().getLocation())) { PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getName()); Claim claim = this.dataStore.getClaimAt(event.getBlock().getLocation(), false, playerData.lastClaim); if (claim == null) return; String noEntitiesReason = claim.allowMoreEntities(); if (noEntitiesReason != null) { GriefPrevention.sendMessage(event.getPlayer(), TextMode.Err, noEntitiesReason); event.setCancelled(true); return; } } }
// when a creature spawns... @EventHandler(priority = EventPriority.LOWEST) public void onEntitySpawn(CreatureSpawnEvent event) { LivingEntity entity = event.getEntity(); // these rules apply only to creative worlds if (!GriefPrevention.instance.creativeRulesApply(entity.getLocation())) return; // chicken eggs and breeding could potentially make a mess in the wilderness, once griefers get // involved SpawnReason reason = event.getSpawnReason(); if (reason != SpawnReason.SPAWNER_EGG && reason != SpawnReason.BUILD_IRONGOLEM && reason != SpawnReason.BUILD_SNOWMAN) { event.setCancelled(true); return; } // otherwise, just apply the limit on total entities per claim (and no spawning in the // wilderness!) Claim claim = this.dataStore.getClaimAt(event.getLocation(), false, null); if (claim == null || claim.allowMoreEntities() != null) { event.setCancelled(true); return; } }
/** Computes the scores for all features on the board. */ public List<FeatureScore> computeFinalScores() { // we use this set to track which claim groups we've already processed Set<Integer> processedClaims = Sets.newHashSet(); // check all features on all tiles for potential scores List<FeatureScore> scores = Lists.newArrayList(); for (Placement play : _plays.values()) { Claim claim = getClaim(play); for (Feature f : play.tile.terrain.features) { // ignore features that aren't completable (e.g. GRASS) if (!COMPLETABLES.contains(f.type)) continue; // determine whether or not we've already processed this claim int group = claim.getClaimGroup(f); if (processedClaims.contains(group)) continue; processedClaims.add(group); // determine who will earn points for this claim Set<Integer> scorers = getScorers(group); // if we have no scorers, the feature is unclaimed; skip it if (scorers.isEmpty()) continue; // if we made it this far, we may have something to report int score = computeFeatureScore(play, f); if (score != 0) { scores.add(new FeatureScore(f, scorers, score, getPiecens(group))); } } } return scores; }
/** Remove the given claims in one go. */ @Transactional @Secured(BF_CLAIM_DELETE) public void remove(Collection<Claim> claims) { for (Claim claim : claims) { claim.remove(); } }
// when a vehicle is damaged @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onVehicleDamage(VehicleDamageEvent event) { // all of this is anti theft code if (!GriefPrevention.instance.config_claims_preventTheft) return; // determine which player is attacking, if any Player attacker = null; Entity damageSource = event.getAttacker(); if (damageSource instanceof Player) { attacker = (Player) damageSource; } else if (damageSource instanceof Arrow) { Arrow arrow = (Arrow) damageSource; if (arrow.getShooter() instanceof Player) { attacker = (Player) arrow.getShooter(); } } else if (damageSource instanceof ThrownPotion) { ThrownPotion potion = (ThrownPotion) damageSource; if (potion.getShooter() instanceof Player) { attacker = (Player) potion.getShooter(); } } // NOTE: vehicles can be pushed around. // so unless precautions are taken by the owner, a resourceful thief might find ways to steal // anyway Claim cachedClaim = null; PlayerData playerData = null; if (attacker != null) { playerData = this.dataStore.getPlayerData(attacker.getName()); cachedClaim = playerData.lastClaim; } Claim claim = this.dataStore.getClaimAt(event.getVehicle().getLocation(), false, cachedClaim); // if it's claimed if (claim != null) { // if damaged by anything other than a player, cancel the event if (attacker == null) { event.setCancelled(true); } // otherwise the player damaging the entity must have permission else { String noContainersReason = claim.allowContainers(attacker); if (noContainersReason != null) { event.setCancelled(true); GriefPrevention.sendMessage( attacker, TextMode.Err, Messages.NoDamageClaimedEntity, claim.getOwnerName()); } // cache claim for later if (playerData != null) { playerData.lastClaim = claim; } } } }
// the number of claim blocks a player has available for claiming land public int getRemainingClaimBlocks() { // accrued blocks + bonus blocks + permission bonus blocks int remainingBlocks = this.getAccruedClaimBlocks() + this.getBonusClaimBlocks() + GriefPreventionPlus.getInstance().getDataStore().getGroupBonusBlocks(this.playerID); for (final Claim claim : this.getClaims()) { remainingBlocks -= claim.getArea(); } return remainingBlocks; }
/** Merge the given claims into one and return the result. */ @Transactional @Secured(BF_CLAIM_UPDATE) public Claim merge(Collection<Claim> claims) { BigDecimal amount = BigDecimal.ZERO; for (Claim claim : claims) { amount = amount.add(claim.getAmount()); } Claim merged = Claim.of(Type.LEGITIMATE, "Merged claim", "Merged claim", amount); merged.persist(); remove(claims); return merged; }
public void renameCity(String oldName, String newName) { for (Claim claim : claimMap.values()) { if (oldName.equals(claim.getCityName())) claim.setCityName(newName); } City city = cityCache.get(oldName); cityCache.remove(oldName); city.rename(newName); cityCache.put(newName, city); for (PlayerCache pc : playerCache.values()) { if (oldName.equals(pc.getCity())) pc.setCity(newName); } }
public Vector<Claim> getClaims() { if (this.claims == null) { int totalClaimsArea = 0; this.claims = new Vector<Claim>(); // find all the claims belonging to this player and note them for // future reference for (final Claim claim : GriefPreventionPlus.getInstance().getDataStore().claims.values()) { if (this.playerID.equals(claim.getOwnerID())) { this.claims.add(claim); totalClaimsArea += claim.getArea(); } } // ensure player has claim blocks for his claims, and at least the // minimum accrued this.loadDataFromSecondaryStorage(); // if total claimed area is more than total blocks available int totalBlocks = this.accruedClaimBlocks + this.getBonusClaimBlocks() + GriefPreventionPlus.getInstance().getDataStore().getGroupBonusBlocks(this.playerID); if (totalBlocks < totalClaimsArea) { // try to fix it by adding to accrued blocks this.accruedClaimBlocks = totalClaimsArea; if (this.accruedClaimBlocks > GriefPreventionPlus.getInstance().config.claims_maxAccruedBlocks) { // remember to respect the maximum on accrued blocks this.accruedClaimBlocks = GriefPreventionPlus.getInstance().config.claims_maxAccruedBlocks; } // if that didn't fix it, then make up the difference with bonus // blocks totalBlocks = this.accruedClaimBlocks + this.getBonusClaimBlocks() + GriefPreventionPlus.getInstance() .getDataStore() .getGroupBonusBlocks(this.playerID); if (totalBlocks < totalClaimsArea) { this.bonusClaimBlocks += totalClaimsArea - totalBlocks; } } } return this.claims; }
// restores nature in multiple chunks, as described by a claim instance // this restores all chunks which have ANY number of claim blocks from this claim in them // if the claim is still active (in the data store), then the claimed blocks will not be changed // (only the area bordering the claim) public void restoreClaim(Claim claim, long delayInTicks) { // admin claims aren't automatically cleaned up when deleted or abandoned if (claim.isAdminClaim()) return; // it's too expensive to do this for huge claims if (claim.getArea() > 10000) return; Chunk lesserChunk = claim.getLesserBoundaryCorner().getChunk(); Chunk greaterChunk = claim.getGreaterBoundaryCorner().getChunk(); for (int x = lesserChunk.getX(); x <= greaterChunk.getX(); x++) for (int z = lesserChunk.getZ(); z <= greaterChunk.getZ(); z++) { Chunk chunk = lesserChunk.getWorld().getChunkAt(x, z); this.restoreChunk( chunk, this.getSeaLevel(chunk.getWorld()) - 15, false, delayInTicks, null); } }
public void deleteCity(String city) { Collection<Claim> cc = claimMap.values(); Iterator<Claim> iter = cc.iterator(); while (iter.hasNext()) { Claim claim = iter.next(); if (city.equals(claim.getCityName())) iter.remove(); } cityCache.remove(city); for (PlayerCache pc : playerCache.values()) { if (city.equals(pc.getCity())) { pc.setCity(null); pc.setRank(null); } } }
public void unclaimAll(String cityName, Claim claim) { City city = cityCache.get(cityName); Collection<Claim> cc = claimMap.values(); Iterator<Claim> iter = cc.iterator(); while (iter.hasNext()) { Claim c = iter.next(); if (c.getCityName().equals(cityName)) { iter.remove(); city.removeClaim(c); } } claimMap.put(claim.toString(), claim); city.addClaim(claim, null, null, null, null); city.setUsedClaims(1); city.removeAllPlots(); }
public String allowBuild(Player player, Location location) { PlayerData playerData = this.dataStore.getPlayerData(player.getName()); Claim claim = this.dataStore.getClaimAt(location, false, playerData.lastClaim); WorldConfig wc = GriefPrevention.instance.getWorldCfg(player.getWorld()); // exception: administrators in ignore claims mode and special player accounts created by server // mods if (playerData.ignoreClaims || wc.getModsIgnoreClaimsAccounts().contains(player.getName())) return null; // wilderness rules if (claim == null) { // no building in the wilderness in creative mode if (this.creativeRulesApply(location)) { String reason = this.dataStore.getMessage(Messages.NoBuildOutsideClaims) + " " + this.dataStore.getMessage(Messages.CreativeBasicsDemoAdvertisement); if (player.hasPermission("griefprevention.ignoreclaims")) reason += " " + this.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement); return reason; } // no building in survival wilderness when that is configured else if (wc.getApplyTrashBlockRules() && wc.getClaimsEnabled()) { if (wc.getTrashBlockPlacementBehaviour().Allowed(location, player).Denied()) return this.dataStore.getMessage(Messages.NoBuildOutsideClaims) + " " + this.dataStore.getMessage(Messages.SurvivalBasicsDemoAdvertisement); else return null; } else { // but it's fine in creative return null; } } // if not in the wilderness, then apply claim rules (permissions, etc) else { // cache the claim for later reference playerData.lastClaim = claim; return claim.allowBuild(player); } }
public void removeClaim(Claim claim) { claimMap.remove(claim.toString()); Chunk chunk = getServer().getWorld(claim.getWorld()).getChunkAt(claim.getX(), claim.getZ()); Block minBlock = chunk.getBlock(0, 0, 0); Block maxBlock = chunk.getBlock(15, 0, 15); int xmin = minBlock.getX(); int zmin = minBlock.getZ(); int xmax = maxBlock.getX(); int zmax = maxBlock.getZ(); City city = getCity(claim.getCityName()); ArrayList<Integer> idList = city.removeIntersectingPlots(xmin, zmin, xmax, zmax); for (int i : idList) { database.removePlot(i); } city.setUsedClaims(city.getUsedClaims() - 1); city.removeClaim(claim); }
@Override public void run() { // for each claim involved in this siege for (int i = 0; i < this.siegeData.claims.size(); i++) { // lock the doors Claim claim = this.siegeData.claims.get(i); claim.doorsOpen = false; // eject bad guys Player[] onlinePlayers = GriefPrevention.instance.getServer().getOnlinePlayers(); for (int j = 0; j < onlinePlayers.length; j++) { Player player = onlinePlayers[j]; if (claim.contains(player.getLocation(), false, false) && claim.allowAccess(player) != null) { GriefPrevention.sendMessage( player, TextMode.Err, "Looting time is up! Ejected from the claim."); GriefPrevention.instance.ejectPlayer(player); } } } }
/** Computes the scores for all features involved in the supplied placement. */ public List<FeatureScore> computeScores(Placement play) { List<FeatureScore> scores = Lists.newArrayList(); Claim claim = getClaim(play); // check all of the features on this tile for potential scores Set<Integer> groups = Sets.newHashSet(); for (Feature f : play.tile.terrain.features) { // ignore features that aren't completed in this way (e.g. GRASS) if (!COMPLETABLES.contains(f.type)) continue; // make sure we haven't already scored this group; some tiles have disconnected // features that can be linked into the same group int group = claim.getClaimGroup(f); if (groups.contains(group)) continue; groups.add(group); // see who should score this feature Set<Integer> scorers = getScorers(group); // if we have no scorers, the feature is unclaimed; skip it if (scorers.isEmpty()) continue; // if we made it this far, we may have something to report int score = computeFeatureScore(play, f); if (score != 0) { scores.add(new FeatureScore(f, scorers, score, getPiecens(group))); } } // we may have also completed a cloister, so we check that as well for (Location nloc : play.loc.neighborhood()) { Placement nplay = _plays.get(nloc); if (nplay == null) continue; // check whether this tile has a piecen upon't Piecen p = _piecens.get(nloc); if (p == null) continue; // check whether this tile contains a cloister feature Feature cf = null; for (Feature f : nplay.tile.terrain.features) { if (f.type == Feature.Type.CLOISTER) { cf = f; break; } } if (cf == null) continue; // make sure the piecen is on the cloister if (_piecenGroups.get(p.loc) != getClaim(nplay).getClaimGroup(cf)) continue; // finally, score the cloister, which will always have only one scorer, one involved // piecen, and a non-zero score (simple!) scores.add( new FeatureScore( cf, Collections.singleton(p.ownerIdx), computeFeatureScore(nplay, cf), Collections.singletonList(p))); } return scores; }
// when an entity is damaged @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onEntityDamage(EntityDamageEvent event) { // only actually interested in entities damaging entities (ignoring environmental damage) if (!(event instanceof EntityDamageByEntityEvent)) return; // monsters are never protected if (event.getEntity() instanceof Monster) return; EntityDamageByEntityEvent subEvent = (EntityDamageByEntityEvent) event; // determine which player is attacking, if any Player attacker = null; Entity damageSource = subEvent.getDamager(); if (damageSource instanceof Player) { attacker = (Player) damageSource; } else if (damageSource instanceof Arrow) { Arrow arrow = (Arrow) damageSource; if (arrow.getShooter() instanceof Player) { attacker = (Player) arrow.getShooter(); } } else if (damageSource instanceof ThrownPotion) { ThrownPotion potion = (ThrownPotion) damageSource; if (potion.getShooter() instanceof Player) { attacker = (Player) potion.getShooter(); } } // if the attacker is a player and defender is a player (pvp combat) if (attacker != null && event.getEntity() instanceof Player) { // FEATURE: prevent pvp in the first minute after spawn, and prevent pvp when one or both // players have no inventory // doesn't apply when the attacker has the no pvp immunity permission // this rule is here to allow server owners to have a world with no spawn camp protection by // assigning permissions based on the player's world if (attacker.hasPermission("griefprevention.nopvpimmunity")) return; Player defender = (Player) (event.getEntity()); PlayerData defenderData = this.dataStore.getPlayerData(((Player) event.getEntity()).getName()); PlayerData attackerData = this.dataStore.getPlayerData(attacker.getName()); // otherwise if protecting spawning players if (GriefPrevention.instance.config_pvp_protectFreshSpawns) { if (defenderData.pvpImmune) { event.setCancelled(true); GriefPrevention.sendMessage(attacker, TextMode.Err, Messages.ThatPlayerPvPImmune); return; } if (attackerData.pvpImmune) { event.setCancelled(true); GriefPrevention.sendMessage(attacker, TextMode.Err, Messages.CantFightWhileImmune); return; } } // FEATURE: prevent players who very recently participated in pvp combat from hiding inventory // to protect it from looting // FEATURE: prevent players who are in pvp combat from logging out to avoid being defeated long now = Calendar.getInstance().getTimeInMillis(); defenderData.lastPvpTimestamp = now; defenderData.lastPvpPlayer = attacker.getName(); attackerData.lastPvpTimestamp = now; attackerData.lastPvpPlayer = defender.getName(); } // FEATURE: protect claimed animals, boats, minecarts // NOTE: animals can be lead with wheat, vehicles can be pushed around. // so unless precautions are taken by the owner, a resourceful thief might find ways to steal // anyway // if theft protection is enabled if (event instanceof EntityDamageByEntityEvent) { // if the entity is an non-monster creature (remember monsters disqualified above), or a // vehicle if ((subEvent.getEntity() instanceof Creature && GriefPrevention.instance.config_claims_protectCreatures)) { Claim cachedClaim = null; PlayerData playerData = null; if (attacker != null) { playerData = this.dataStore.getPlayerData(attacker.getName()); cachedClaim = playerData.lastClaim; } Claim claim = this.dataStore.getClaimAt(event.getEntity().getLocation(), false, cachedClaim); // if it's claimed if (claim != null) { // if damaged by anything other than a player, cancel the event if (attacker == null) { event.setCancelled(true); } // otherwise the player damaging the entity must have permission else { String noContainersReason = claim.allowContainers(attacker); if (noContainersReason != null) { event.setCancelled(true); GriefPrevention.sendMessage( attacker, TextMode.Err, Messages.NoDamageClaimedEntity, claim.getOwnerName()); } // cache claim for later if (playerData != null) { playerData.lastClaim = claim; } } } } } }
public City getCityAt(int x, int z, String world) { Claim claim = claimMap.get(new Claim(world, x, z).toString()); if (claim == null) return null; return cityCache.get(claim.getCityName()); }
public Claimed( final Claim source, final SimTime time, final AgentID senderID, final AgentID receiverID) { super(source.getID(), senderID.getModelID(), senderID, receiverID); replyToId = source.getID(); }
public void addClaim(Claim claim) { claimMap.put(claim.toString(), claim); com.sethcran.cityscape.Claim north = getClaimAt(claim.getX(), claim.getZ() + 1, claim.getWorld()); com.sethcran.cityscape.Claim east = getClaimAt(claim.getX() + 1, claim.getZ(), claim.getWorld()); com.sethcran.cityscape.Claim south = getClaimAt(claim.getX(), claim.getZ() - 1, claim.getWorld()); com.sethcran.cityscape.Claim west = getClaimAt(claim.getX() - 1, claim.getZ(), claim.getWorld()); if (north != null) { if (!north.getCityName().equals(claim.getCityName())) north = null; } if (east != null) { if (!east.getCityName().equals(claim.getCityName())) east = null; } if (south != null) { if (!south.getCityName().equals(claim.getCityName())) south = null; } if (west != null) { if (!west.getCityName().equals(claim.getCityName())) west = null; } getCity(claim.getCityName()).addClaim(claim, north, east, south, west); }