public ObjectLandClaimCanUpgradeCheckResult ServerRemote_UpgradeStructure( IStaticWorldObject oldWorldObjectLandClaim, IProtoObjectLandClaim upgradeStructure) { this.VerifyGameObject(oldWorldObjectLandClaim); var character = ServerRemoteContext.Character; var result = this.SharedCanUpgrade(oldWorldObjectLandClaim, upgradeStructure, character, out var upgradeEntry); if (result != ObjectLandClaimCanUpgradeCheckResult.Success) { return(result); } // consume items upgradeEntry.ServerDestroyRequiredItems(character); // upgrade (it will destroy an existing structure and place new in its place) var upgradedWorldObjectLandClaim = LandClaimSystem.ServerUpgrade(oldWorldObjectLandClaim, upgradeStructure, character); // notify client (to play a sound) ConstructionPlacementSystem.Instance.ServerNotifyOnStructurePlacedOrRelocated( upgradedWorldObjectLandClaim, character); return(result); }
public async void ClientUpgrade(IStaticWorldObject worldObjectLandClaim, IProtoObjectLandClaim upgradeStructure) { var checkResult = this.SharedCanUpgrade( worldObjectLandClaim, upgradeStructure, Client.Characters.CurrentPlayerCharacter, out _); if (checkResult == ObjectLandClaimCanUpgradeCheckResult.Success) { // client check successful - send the upgrade request to server checkResult = await this.CallServer( _ => _.ServerRemote_UpgradeStructure(worldObjectLandClaim, upgradeStructure)); // process the upgrade result from server if (checkResult == ObjectLandClaimCanUpgradeCheckResult.Success) { NotificationSystem.ClientShowNotification( NotificationUpgraded_Title, NotificationUpgraded_Message, color: NotificationColor.Good, icon: this.Icon); return; } } DialogWindow.ShowMessage(DialogCannotUpgrade, text: checkResult.GetDescription(), closeByEscapeKey: true); }
// need to verify that area bounds will not intersect with the any existing areas (except from the same founder) public static bool SharedCheckCanPlaceOrUpgradeLandClaimThere( IProtoObjectLandClaim protoObjectLandClaim, Vector2Ushort centerTilePosition, ICharacter forCharacter) { var newAreaBounds = SharedCalculateLandClaimAreaBounds( centerTilePosition, protoObjectLandClaim.LandClaimSize); foreach (var area in sharedLandClaimAreas) { var areaBoundsDirect = SharedGetLandClaimAreaBounds(area); var areaBoundsWithPadding = areaBoundsDirect.Inflate(LandClaimAreaGracePaddingSize, LandClaimAreaGracePaddingSize); if (!areaBoundsWithPadding.IntersectsLoose(newAreaBounds)) { // there is no area (even with the padding/grace area) continue; } if (!SharedIsOwnedArea(area, forCharacter)) { // the grace/padding area of another player's land claim owner return(false); } } return(true); }
public ViewModelWindowLandClaim( IStaticWorldObject landClaimWorldObject, ILogicObject area) { this.landClaimWorldObject = landClaimWorldObject; this.privateState = LandClaimArea.GetPrivateState(area); var protoLandClaim = (IProtoObjectLandClaim)landClaimWorldObject.ProtoStaticWorldObject; var canEditOwners = protoLandClaim .SharedCanEditOwners(landClaimWorldObject, ClientCurrentCharacterHelper.Character); this.ViewModelOwnersEditor = new ViewModelWorldObjectOwnersEditor( this.privateState.LandOwners, callbackServerSetOwnersList: ownersList => LandClaimSystem.ClientSetAreaOwners( area, ownersList), title: AccessListTitle + ":", emptyListMessage: AccessListEmpty, canEditOwners: canEditOwners, // exclude founder name ownersListFilter: name => name != this.FounderName, maxOwnersListLength: LandClaimSystemConstants.SharedLandClaimOwnersMax, displayedOwnersNumberAdjustment: -1); this.protoObjectLandClaim = (IProtoObjectLandClaim)this.landClaimWorldObject.ProtoStaticWorldObject; var upgrade = this.protoObjectLandClaim.ConfigUpgrade.Entries.FirstOrDefault(); if (upgrade is not null) { this.ViewModelStructureUpgrade = new ViewModelStructureUpgrade(upgrade); this.ViewModelProtoLandClaimInfoUpgrade = new ViewModelProtoLandClaimInfo( (IProtoObjectLandClaim)upgrade.ProtoStructure); } var objectPublicState = landClaimWorldObject.GetPublicState <ObjectLandClaimPublicState>(); objectPublicState.ClientSubscribe( _ => _.LandClaimAreaObject, _ => this.RefreshSafeStorageAndPowerGrid(), this); this.RefreshSafeStorageAndPowerGrid(); this.ViewModelProtoLandClaimInfoCurrent = new ViewModelProtoLandClaimInfo(this.protoObjectLandClaim); ItemsContainerLandClaimSafeStorage.ClientSafeItemsSlotsCapacityChanged += this.SafeItemsSlotsCapacityChangedHandler; this.RequestDecayInfoTextAsync(); this.ViewModelShieldProtectionControl = new ViewModelShieldProtectionControl( LandClaimSystem.SharedGetLandClaimAreasGroup(area)); }
public ViewModelBrokenObjectLandClaimTooltip( IStaticWorldObject objectLandClaim, ObjectLandClaimPublicState publicState) { this.objectLandClaim = objectLandClaim; this.protoObjectLandClaim = (IProtoObjectLandClaim)objectLandClaim.ProtoStaticWorldObject; this.publicState = publicState; publicState.ClientSubscribe( _ => _.ServerTimeForDestruction, isWatered => { this.RefreshDataFromServer(); }, this); this.RefreshDataFromServer(); }
public async void ClientUpgrade( IStaticWorldObject worldObjectLandClaim, IProtoObjectLandClaim protoStructureUpgrade) { var checkResult = this.SharedCanUpgrade( worldObjectLandClaim, protoStructureUpgrade, Client.Characters.CurrentPlayerCharacter, out _); if (checkResult == ObjectLandClaimCanUpgradeCheckResult.Success) { // client check successful - send the upgrade request to server checkResult = await this.CallServer( _ => _.ServerRemote_UpgradeStructure(worldObjectLandClaim, protoStructureUpgrade)); // process the upgrade result from server if (checkResult == ObjectLandClaimCanUpgradeCheckResult.Success) { NotificationSystem.ClientShowNotification( NotificationUpgraded_Title, NotificationUpgraded_Message, color: NotificationColor.Good, icon: this.Icon); return; } } string errorMessage = checkResult switch { ObjectLandClaimCanUpgradeCheckResult.ErrorFactionPermissionRequired => string.Format(CoreStrings.Faction_Permission_Required_Format, CoreStrings.Faction_Permission_LandClaimManagement_Title), ObjectLandClaimCanUpgradeCheckResult.ErrorFactionLandClaimNumberLimitWillBeExceeded => CoreStrings.Faction_LandClaimNumberLimit_Reached + "[br]" + CoreStrings.Faction_LandClaimNumberLimit_CanIncrease, _ => checkResult.GetDescription() }; DialogWindow.ShowDialog(DialogCannotUpgrade, text: errorMessage, textAlignment: TextAlignment.Left, closeByEscapeKey: true); }
public ObjectLandClaimCanUpgradeCheckResult ServerRemote_UpgradeStructure( IStaticWorldObject oldWorldObjectLandClaim, IProtoObjectLandClaim upgradeStructure) { this.VerifyGameObject(oldWorldObjectLandClaim); var character = ServerRemoteContext.Character; var result = this.SharedCanUpgrade(oldWorldObjectLandClaim, upgradeStructure, character, out var upgradeEntry); if (result != ObjectLandClaimCanUpgradeCheckResult.Success) { return(result); } // consume items upgradeEntry.ServerDestroyRequiredItems(character); // copy all items to temp container var oldStorage = GetPrivateState(oldWorldObjectLandClaim).ItemsContainer; var tempStorageOwner = Server.World.CreateLogicObject <LogicObjectTempItemsContainerHolder>(); var tempStorage = Server.Items.CreateContainer( owner: tempStorageOwner, // we must set an owner, unfortunately slotsCount: (byte)oldStorage.OccupiedSlotsCount); Server.Items.TryMoveAllItems(oldStorage, tempStorage); // upgrade (it will destroy an existing structure and place new in its place) var upgradedWorldObjectLandClaim = LandClaimSystem.ServerUpgrade(oldWorldObjectLandClaim, upgradeStructure, character); // move all items from temp container to the upgraded land claim var newStorage = GetPrivateState(upgradedWorldObjectLandClaim).ItemsContainer; Server.Items.TryMoveAllItems(tempStorage, newStorage); Server.Items.DestroyContainer(tempStorage); Server.World.DestroyObject(tempStorageOwner); // notify client (to play sound) ConstructionPlacementSystem.Instance.ServerOnStructurePlaced(upgradedWorldObjectLandClaim, character); return(result); }
public ViewModelWindowLandClaim( IStaticWorldObject landClaimWorldObject, ILogicObject area) { this.landClaimWorldObject = landClaimWorldObject; this.privateState = LandClaimArea.GetPrivateState(area); var protoStructureWithOwnersList = ((IProtoObjectWithOwnersList)landClaimWorldObject.ProtoStaticWorldObject); var canEditOwners = protoStructureWithOwnersList .SharedCanEditOwners(landClaimWorldObject, ClientCurrentCharacterHelper.Character); this.ViewModelOwnersEditor = new ViewModelWorldObjectOwnersEditor( this.privateState.LandOwners, callbackServerSetOwnersList: ownersList => LandClaimSystem.ClientSetAreaOwners( area, ownersList), title: AccessListTitle + ":", emptyListMessage: AccessListEmpty, canEditOwners: canEditOwners, // exclude founder name ownersListFilter: name => name != this.FounderName); this.protoObjectLandClaim = (IProtoObjectLandClaim)this.landClaimWorldObject.ProtoStaticWorldObject; var upgrade = this.protoObjectLandClaim.ConfigUpgrade.Entries.FirstOrDefault(); if (upgrade != null) { this.ViewModelStructureUpgrade = new ViewModelStructureUpgrade(upgrade); this.ViewModelProtoLandClaimInfoUpgrade = new ViewModelProtoLandClaimInfo( (IProtoObjectLandClaim)upgrade.ProtoStructure); } this.ViewModelItemsContainerExchange = new ViewModelItemsContainerExchange( landClaimWorldObject.GetPrivateState <ObjectLandClaimPrivateState>().ItemsContainer, callbackTakeAllItemsSuccess: () => { }) { IsContainerTitleVisible = false }; this.ViewModelProtoLandClaimInfoCurrent = new ViewModelProtoLandClaimInfo(this.protoObjectLandClaim); }
private static void SetupBoundsForLandClaimsInScope( IClientSceneObject sceneObject, Vector2D sceneObjectPosition, Vector2Ushort originTilePosition, RectangleInt originBounds, IProtoObjectLandClaim originProtoObjectLandClaim) { var landClaims = Api.Client.World.GetStaticWorldObjectsOfProto <IProtoObjectLandClaim>(); foreach (var landClaim in landClaims) { var protoObjectLandClaim = (IProtoObjectLandClaim)landClaim.ProtoGameObject; var landClaimCenterPosition = LandClaimSystem .SharedCalculateLandClaimObjectCenterTilePosition( landClaim.TilePosition, protoObjectLandClaim); var landClaimBounds = LandClaimSystem.SharedCalculateLandClaimAreaBounds( landClaimCenterPosition, protoObjectLandClaim.LandClaimWithGraceAreaSize); var intersectionDepth = CalculateIntersectionDepth(originBounds, landClaimBounds); if (intersectionDepth < 0) { // no intersection continue; } intersectionDepth = (intersectionDepth + 1) / 2; intersectionDepth = Math.Min(intersectionDepth, originProtoObjectLandClaim.LandClaimGraceAreaPaddingSizeOneDirection + 1); var exceptBounds = originBounds.Inflate(-intersectionDepth); using var tempList = Api.Shared.WrapObjectInTempList(exceptBounds); AddBoundLabels(sceneObject, sceneObjectPosition, exceptBounds: tempList.AsList(), protoObjectLandClaim, positionOffset: landClaimCenterPosition.ToVector2D() - originTilePosition.ToVector2D()); } }
private static void AddBoundSquares( IClientSceneObject sceneObject, IProtoObjectLandClaim protoObjectLandClaim, Vector2D positionOffset) { positionOffset += (1, 1); var ui = Api.Client.UI; var from = protoObjectLandClaim.LandClaimSize / 2; var to = protoObjectLandClaim.LandClaimWithGraceAreaSize / 2; for (var v = from; v <= to; v++) { ui.AttachControl( sceneObject, positionOffset: positionOffset, uiElement: new Rectangle() { Width = v * 2 * ScriptingConstants.TileSizeVirtualPixels, Height = v * 2 * ScriptingConstants.TileSizeVirtualPixels, Stroke = BrushBoundWhite, StrokeThickness = 4 }, isFocusable: false, isScaleWithCameraZoom: true); ui.AttachControl( sceneObject, positionOffset: positionOffset, uiElement: new Rectangle() { Width = v * 2 * ScriptingConstants.TileSizeVirtualPixels, Height = v * 2 * ScriptingConstants.TileSizeVirtualPixels, Stroke = BrushBoundBlack, StrokeThickness = 2 }, isFocusable: false, isScaleWithCameraZoom: true); } }
public static void AddBlueprintRenderer(Vector2Ushort tilePosition, IProtoObjectLandClaim protoObjectLandClaim) { RendererManagerGraceAreas.RegisterBlueprint(tilePosition, protoObjectLandClaim); RendererManagerOwnedByPlayer.RegisterBlueprint(tilePosition, protoObjectLandClaim); }
public ObjectLandClaimCanUpgradeCheckResult SharedCanUpgrade( IStaticWorldObject worldObjectLandClaim, IProtoObjectLandClaim protoUpgradedLandClaim, ICharacter character, out IConstructionUpgradeEntryReadOnly upgradeEntry, bool writeErrors = true) { if (!this.SharedCanInteract(character, worldObjectLandClaim, writeToLog: writeErrors)) { upgradeEntry = null; return(ObjectLandClaimCanUpgradeCheckResult.ErrorUnknown); } upgradeEntry = null; foreach (var entry in this.ConfigUpgrade.Entries) { if (entry.ProtoStructure == protoUpgradedLandClaim) { upgradeEntry = entry; break; } } var currentLandClaimArea = GetPublicState(worldObjectLandClaim).LandClaimAreaObject; var founderName = LandClaimArea.GetPrivateState(currentLandClaimArea).LandClaimFounder; var result = ObjectLandClaimCanUpgradeCheckResult.Success; if (upgradeEntry == null) { result = ObjectLandClaimCanUpgradeCheckResult.ErrorUnknown; } if (result == ObjectLandClaimCanUpgradeCheckResult.Success) { if (character.Name != founderName && !CreativeModeSystem.SharedIsInCreativeMode(character)) { result = ObjectLandClaimCanUpgradeCheckResult.ErrorNotFounder; } } if (result == ObjectLandClaimCanUpgradeCheckResult.Success) { // validate player know the tech, have enough items, etc if (!upgradeEntry.CheckRequirementsSatisfied(character)) { upgradeEntry = null; result = ObjectLandClaimCanUpgradeCheckResult.ErrorRequirementsNotSatisfied; } } if (result == ObjectLandClaimCanUpgradeCheckResult.Success) { // check there will be no intersection with other areas var landClaimCenterTilePosition = LandClaimSystem.SharedCalculateLandClaimObjectCenterTilePosition(worldObjectLandClaim); if (!LandClaimSystem.SharedCheckCanPlaceOrUpgradeLandClaimThere( protoUpgradedLandClaim, landClaimCenterTilePosition, character)) { result = ObjectLandClaimCanUpgradeCheckResult.ErrorAreaIntersection; } } if (result == ObjectLandClaimCanUpgradeCheckResult.Success) { if (!InteractionCheckerSystem.SharedHasInteraction(character, worldObjectLandClaim, requirePrivateScope: true)) { result = ObjectLandClaimCanUpgradeCheckResult.ErrorNoActiveInteraction; } } if (result == ObjectLandClaimCanUpgradeCheckResult.Success) { if (LandClaimSystem.SharedIsUnderRaidBlock(character, worldObjectLandClaim)) { // the building is in an area under the raid LandClaimSystem.SharedSendNotificationActionForbiddenUnderRaidblock(character); result = ObjectLandClaimCanUpgradeCheckResult.ErrorUnderRaid; } } if (writeErrors && result != ObjectLandClaimCanUpgradeCheckResult.Success) { Logger.Warning( $"Can\'t upgrade: {worldObjectLandClaim} to {protoUpgradedLandClaim}: error code - {result}", character); } return(result); }
public ProtoObjectLandClaimViewModel([NotNull] IProtoObjectLandClaim landClaim) : base(landClaim) { }
public static void SetupBlueprint( Tile tile, IClientBlueprint blueprint, IProtoObjectLandClaim protoObjectLandClaim) { if (!blueprint.IsEnabled) { return; } var sceneObject = blueprint.SceneObject; var world = Api.Client.World; var rendering = Api.Client.Rendering; var character = ClientCurrentCharacterHelper.Character; var startTilePosition = LandClaimSystem.SharedCalculateLandClaimObjectCenterTilePosition( tile.Position, protoObjectLandClaim); var sizeWithGraceArea = protoObjectLandClaim.LandClaimWithGraceAreaSize; var blueprintAreaBounds = LandClaimSystem.SharedCalculateLandClaimAreaBounds(startTilePosition, sizeWithGraceArea); SetupBoundsForLandClaimsInScope(sceneObject, sceneObjectPosition: tile.Position.ToVector2D(), startTilePosition, blueprintAreaBounds, protoObjectLandClaim); using var tempListExceptBounds = Api.Shared.GetTempList <RectangleInt>(); CollectLabelExclusionBoundsForBlueprint(blueprintAreaBounds, tempListExceptBounds.AsList()); ClientLandClaimAreaManager.AddBlueprintRenderer(startTilePosition, protoObjectLandClaim); // additionally highlight the restricted tiles var halfSize = sizeWithGraceArea / 2; for (var x = 1 - halfSize; x <= halfSize; x++) { for (var y = 1 - halfSize; y <= halfSize; y++) { var checkTile = world.GetTile(startTilePosition.X + x, startTilePosition.Y + y, logOutOfBounds: false); ProcessFutureLandClaimAreaTile(checkTile, x, y); } } AddBoundSquares(sceneObject, protoObjectLandClaim, positionOffset: (0, 0)); AddBoundLabels(sceneObject, sceneObjectPosition: tile.Position.ToVector2D(), exceptBounds: tempListExceptBounds.AsList(), protoObjectLandClaim, positionOffset: (0, 0)); void ProcessFutureLandClaimAreaTile(Tile checkTile, int offsetX, int offsetY) { if (!checkTile.IsValidTile) { return; } var isRestrictedTile = IsRestrictedTile(checkTile); if (!isRestrictedTile) { foreach (var neighborTile in checkTile.EightNeighborTiles) { if (IsRestrictedTile(neighborTile)) { isRestrictedTile = true; break; } } } if (!isRestrictedTile) { return; } // display red tile as player cannot construct there var tileRenderer = rendering.CreateSpriteRenderer( sceneObject, ClientLandClaimGroupRenderer.TextureResourceLandClaimAreaCell, DrawOrder.Overlay); tileRenderer.RenderingMaterial = ClientBlueprintRestrictedTileRenderingMaterial; tileRenderer.SortByWorldPosition = false; tileRenderer.Scale = 1; tileRenderer.PositionOffset = (offsetX + 1, offsetY + 1); } bool IsRestrictedTile(Tile t) => t.IsCliffOrSlope || t.ProtoTile.Kind != TileKind.Solid || t.ProtoTile.IsRestrictingConstruction || !LandClaimSystem.SharedIsPositionInsideOwnedOrFreeArea( t.Position, character, addGracePaddingWithoutBuffer: true); }
private static void AddBoundLabels( IClientSceneObject sceneObject, Vector2D sceneObjectPosition, List <RectangleInt> exceptBounds, IProtoObjectLandClaim protoObjectLandClaim, Vector2D positionOffset) { var cameraFrustrum = Api.Client.Rendering.WorldCameraCurrentViewWorldBounds; cameraFrustrum = new BoundsDouble(minX: cameraFrustrum.MinX - 1, minY: cameraFrustrum.MinY - 1, maxX: cameraFrustrum.MaxX + 1, maxY: cameraFrustrum.MaxY + 1); var ui = Api.Client.UI; var textBlockStyle = ui.GetApplicationResource <Style>("LandClaimBoundTextBlockStyle"); var from = protoObjectLandClaim.LandClaimSize / 2; var skippedTiers = 1 + (protoObjectLandClaim.LandClaimSize - LandClaimSystem.MinLandClaimSize.Value) / 2; var to = LandClaimSystem.MaxLandClaimSizeWithGraceArea.Value / 2; for (var v = from; v <= to; v++) { string text; if (v == to) { text = CoreStrings.LandClaimPlacementDisplayHelper_LabelBuffer; } else { var tier = v - from; tier += skippedTiers; text = string.Format(CoreStrings.LandClaimPlacementDisplayHelper_LabelTier_Format, tier); } AddLetterSet((v + 0.5, v + 0.5), text); AddLetterSet((-v + 1.5, v + 0.5), text); AddLetterSet((v + 0.5, -v + 1.5), text); AddLetterSet((-v + 1.5, -v + 1.5), text); } void AddLetterSet(Vector2D setOffset, string text) { AddLetter(setOffset + positionOffset); AddLetter((setOffset.X + positionOffset.X, positionOffset.Y + 0.5)); AddLetter((positionOffset.X + 0.5, setOffset.Y + positionOffset.Y)); void AddLetter(Vector2D letterOffset) { var letterWorldPosition = letterOffset + sceneObjectPosition; if (!cameraFrustrum.Contains(letterWorldPosition)) { return; } if (exceptBounds?.Count > 0) { foreach (var exceptBound in exceptBounds) { if (exceptBound.Contains(letterWorldPosition)) { return; } } } ui.AttachControl(sceneObject, positionOffset: letterOffset, uiElement: new TextBlock { Text = text, Style = textBlockStyle }, isFocusable: false, isScaleWithCameraZoom: false); } } }
public ViewModelProtoLandClaimInfo(IProtoObjectLandClaim protoObjectLandClaim) { this.protoObjectLandClaim = protoObjectLandClaim; this.ViewModelStructure = new ViewModelStructure(this.protoObjectLandClaim); }
public static Vector2Ushort SharedCalculateLandClaimObjectCenterTilePosition( Vector2Ushort tilePosition, IProtoObjectLandClaim protoObjectLandClaim) { return(tilePosition.AddAndClamp(protoObjectLandClaim.Layout.Center.ToVector2Int())); }