Post reply

Warning - while you were reading 10 new replies have been posted. You may wish to review your post.
Name:
Email:
Subject:
Message icon:

shortcuts: hit alt+s to submit/post or alt+p to preview


Topic Summary

Posted by: Pollyfun
« on: August 12, 2021, 01:12:42 PM »

Thanks, I've added the same codeline so there's no need to create a new beta just for this.
Posted by: Kronnect
« on: August 12, 2021, 09:15:51 AM »

There's a CountryCreate method already that takes a name and the continent.

I've added a province initializer to the Country constructor (in Country.cs):
Code
		/// <summary>
/// Creates a new country
/// </summary>
/// <param name="name">Name.</param>
/// <param name="continent">Continent.</param>
/// <param name="uniqueId">For user created countries, use a number between 1-999 to uniquely identify this country.</param>
public Country(string name, string continent, int uniqueId) {
this.name = name;
this.continent = continent;
this.regions = new List<Region>();
this.uniqueId = uniqueId;
this.attrib = new JSONObject();
this.mainRegionIndex = -1;
this.provinces = new Province[0];
}
Posted by: Pollyfun
« on: August 11, 2021, 12:50:44 PM »

Thanks, I got it working.

A possible code improvement. It would be good if we could create an empty country, without needing to add a province and a region to it.
Currently I use this code to create a country, and get country.provinces initialized.

Code
Vector2[] pointsArgentine =
{
new Vector2(-0.2f, 0.59f),
new Vector2(-0.1f, 0.59f),
new Vector2(-0.1f, 0.55f),
new Vector2(-0.2f, 0.55f)
};
int countryIndex = CreateCountry("Argentine", pointsArgentine, 11);
CreateProvince("Arg Province 1", countryIndex, pointsArgentine);   // create a province to initialize country.provinces
_map.ProvinceDelete(_map.provinces.Length-1);  // delete province
_map.GetCountry(countryIndex).regions.Clear();  // delete region


It would be great is this was enough:
Code
int countryIndex = CreateCountry("Argentine", 11);

So two parts:
Skipping the points parameter in CreateCountry()
Initializing country.provinces = new Province[0] during CreateCountry() instead of leaving null.


UPDATE: I noticed that the CreateCountry() method was not part of the core WMSK, but from one of the samples.
So I updated it myself.

Code
int CreateCountry(string name, int uniqueId) {
   Country country = new Country(name, "Continent", uniqueId);
   int countryIndex = _map.CountryAdd(country);
   return countryIndex;
}

Initializing country.provinces would still be good though, to not get errors when using it before adding provinces (or creating a dummy province to avoid those errors)
Posted by: Kronnect
« on: August 11, 2021, 10:18:13 AM »

I've refreshed the latest beta with a safety check in that function so it doesn't break if the country doesn't have any region.

The Provinces objects are not cloned so they're the same object in both countries (so CountryAddProvinces / CountryRemoveProvinces should be called in sequence if you're transferring a province from one country to another). The only case where you don't need to use CountryRemoveProvines is during an initial setup for example, where you have all provinces assigned to some kind of global pool or main country and you distribute them to the real countries to finally completely removing the pool country.

You can fully remove a country calling CountryDelete method.
Posted by: Pollyfun
« on: August 11, 2021, 09:21:31 AM »

I've done some testing now. I can assign provinces one at a time. I used this code

Code
_map.CountryRemoveProvinces(province.countryIndex, provincesToAdd, false);
_map.CountryAddProvinces(targetCountryIndex, provincesToAdd, false, false, false);

https://youtu.be/Srceaq6K1-U

It seems stable when shifting the owner forth and back, so that's very positive.

There's still some issues to work out though. When I'm loading the world, and assigning provinces

"Main Country" -> "Argentine"
"Main Country" -> "United Kingdom"

The assigning works so far:
_map.CountrySetProvinces(_map.GetCountryIndex("United Kingdom"), provincesToAddUK, false, false, false);
_map.CountrySetProvinces(_map.GetCountryIndex("Argentine"), provincesToAddArgentine, false, false, false);

But when I try to remove all provinces from "Main Country" the game gets exceptions right afterwards.

Code
_map.CountryRemoveProvinces(_map.GetCountryIndex("Main Country"), provincesToRemoveMainCountry, false);

When provinces belongs both to the sourcecountry and the destinationcountry, is it the same objects or is it clones?
Is there a safe way to delete a country and all it's provinces and regions? (when the provinces and regions also belongs to another country like in this case)
Posted by: Pollyfun
« on: August 09, 2021, 01:11:06 PM »

Sounds good  8) I will try it out soon.
Posted by: Kronnect
« on: August 09, 2021, 12:43:41 PM »

Hi,

The function CountryTransferProvince was replaced by an overload to CountryTransferProvinceRegion in latest version because it was misleading. Both methods operate similarly now, except that the first method requires a province index and the second one allows you to pass a Region. They do the same thing: they will try to extract from the source country and add it to the target country affecting country frontiers, cities, mount points and merging any affected regions (among other limitations, the old CountryTransferProvince method could not remove regions from source country properly because the country regions are different objects).

In latest beta I added 3 new methods:
- CountrySetProvinces
- CountryAddProvinces
- CountryRemoveProvinces

The way they work is quite different to CountryTransferProvince method.

- CountrySetProvinces will replace ALL provinces in a given country with the passed list. This call will also update the country regions by adding all regions from the provinces and merging them (optionally, by default, mergeRegions parameter is true).
- CountryAddProvinces will add ONE OR MORE provinces to an existing country and merge the regions of those provinces into the country regions.
- CountryRemoveProvinces will call CountrySetProvinces but excluding the given provinces.

The key difference here wrt CountryTransferRegion is that there's no substraction operation on the source country which can cause issues with some polygons.

To summarize:
- CountryTransferProvince will extract one province from a source country and add it to a target country. It performs substraction on the origin country polygon and addition to the target country polygon.
- The same result can be achieved by calling CountryRemoveProvinces on the source country and CountryAddProvinces on the target country. In these cases however, the country provinces list and regions are being recreated completely on the source country. There's no substraction. This operation can be slower (should be slower) on countries with many provinces but should be safer as there's no substraction.

For example, to replace the provinces in Spain with just 2 provinces (Sevilla and Cádiz):

Code
                int spain = map.GetCountryIndex("Spain");
                List<Province> provs = new List<Province>();
                provs.Add(map.GetProvince("Sevilla", "Spain"));
                provs.Add(map.GetProvince("Cádiz", "Spain"));
                map.CountrySetProvinces(spain, provs);
                map.Redraw(true);

Then to add Málage province:

Code
                int spain = map.GetCountryIndex("Spain");
                List<Province> provs = new List<Province>();
                provs.Add(map.GetProvince("Málaga", "Spain"));
                map.CountryAddProvinces(spain, provs);
                map.Redraw(true);

Please get the latest beta and let me know how this alternative works better for you (CountryRemoveProvinces + CountryAddProvinces).
Posted by: Pollyfun
« on: August 07, 2021, 08:51:03 PM »

When disabling frontiers and using CountryTransferProvince() for loading provinces and for changing owner one by one, it mostly works. But there's a couple of issues that would be great if they could be fixed. The first one is that regions are not removed from the sourcecountry. I'm using this code:

Code
public bool CountryTransferProvince(int targetCountryIndex, int provinceIndex) {

if (provinceIndex < 0 || targetCountryIndex < 0 || targetCountryIndex >= _countries.Length)
return false;

// Province must belong to another country
Province province = provinces[provinceIndex];
int sourceCountryIndex = province.countryIndex;
if (sourceCountryIndex == targetCountryIndex)
return false;

// Remove province form source country
Country sourceCountry = _countries[sourceCountryIndex];

if (sourceCountry.provinces != null) {
List<Province> sourceProvinces = new List<Province>(sourceCountry.provinces);
if (sourceProvinces.Contains(province)) {
sourceProvinces.Remove(province);
sourceCountry.provinces = sourceProvinces.ToArray();
}
}

// Adds province to target country
Country targetCountry = _countries[targetCountryIndex];
List<Province> destProvinces;
if (targetCountry.provinces == null) {
destProvinces = new List<Province>();
} else {
destProvinces = new List<Province>(targetCountry.provinces);
}
destProvinces.Add(province);
destProvinces.Sort(ProvinceSizeComparer);
targetCountry.provinces = destProvinces.ToArray();

// Update owner index
province.countryIndex = targetCountryIndex;

// Adds province regions to target country regions
bool requireCountryGeometryRefresh = false;
if (province.regions == null) ReadProvincePackedString(province);
int regionsCount = province.regions.Count;
for (int k = 0; k < regionsCount; k++) {
Region provinceRegion = province.regions[k];
if (!targetCountry.Contains(provinceRegion)) {
Region newRegion = provinceRegion.Clone();
newRegion.entity = targetCountry;
targetCountry.regions.Add(newRegion);
requireCountryGeometryRefresh = true;
}

if (sourceCountry.regions.Contains(provinceRegion)) {
sourceCountry.regions.Remove(provinceRegion);
requireCountryGeometryRefresh = true;
}
}

if (requireCountryGeometryRefresh) {
RefreshCountryGeometry(targetCountry);
    }

    return true;
}

There's code to remove the region, but it doesnt' work
Code
if (sourceCountry.regions.Contains(provinceRegion)) {
    sourceCountry.regions.Remove(provinceRegion);
    requireCountryGeometryRefresh = true;
}


Here's a video showing the results.
https://www.youtube.com/watch?v=N2H75ECjwrs

Posted by: Pollyfun
« on: August 07, 2021, 06:04:57 PM »

I've tested more using the new CountryTransferProvinces() when loading countries, and then using the CountryTransferProvinceRegion() method
when changing province owners one at a time. It often works as expected for a few provinces, but then some problem occur. I've recorded two examples.

In this first case I can change owner of 3 provinces but clicking the fourth the game crashes with an exception, and the following call stack.

Code
NullReferenceException: Object reference not set to an instance of an object
WorldMapStrategyKit.Poly2Tri.DTSweep.FlipEdgeEvent (WorldMapStrategyKit.Poly2Tri.DTSweepContext tcx, WorldMapStrategyKit.Poly2Tri.TriangulationPoint ep, WorldMapStrategyKit.Poly2Tri.TriangulationPoint eq, WorldMapStrategyKit.Poly2Tri.DelaunayTriangle t, WorldMapStrategyKit.Poly2Tri.TriangulationPoint p) (at Assets/WorldMapStrategyKit/Scripts/ThirdParty/PolyTri/Triangulation/Delaunay/Sweep/DTSweep.cs:585)
WorldMapStrategyKit.Poly2Tri.DTSweep.FlipEdgeEvent (WorldMapStrategyKit.Poly2Tri.DTSweepContext tcx, WorldMapStrategyKit.Poly2Tri.TriangulationPoint ep, WorldMapStrategyKit.Poly2Tri.TriangulationPoint eq, WorldMapStrategyKit.Poly2Tri.DelaunayTriangle t, WorldMapStrategyKit.Poly2Tri.TriangulationPoint p) (at Assets/WorldMapStrategyKit/Scripts/ThirdParty/PolyTri/Triangulation/Delaunay/Sweep/DTSweep.cs:612)
WorldMapStrategyKit.Poly2Tri.DTSweep.EdgeEvent (WorldMapStrategyKit.Poly2Tri.DTSweepContext tcx, WorldMapStrategyKit.Poly2Tri.TriangulationPoint ep, WorldMapStrategyKit.Poly2Tri.TriangulationPoint eq, WorldMapStrategyKit.Poly2Tri.DelaunayTriangle triangle, WorldMapStrategyKit.Poly2Tri.TriangulationPoint point) (at Assets/WorldMapStrategyKit/Scripts/ThirdParty/PolyTri/Triangulation/Delaunay/Sweep/DTSweep.cs:579)
WorldMapStrategyKit.Poly2Tri.DTSweep.EdgeEvent (WorldMapStrategyKit.Poly2Tri.DTSweepContext tcx, WorldMapStrategyKit.Poly2Tri.TriangulationPoint ep, WorldMapStrategyKit.Poly2Tri.TriangulationPoint eq, WorldMapStrategyKit.Poly2Tri.DelaunayTriangle triangle, WorldMapStrategyKit.Poly2Tri.TriangulationPoint point) (at Assets/WorldMapStrategyKit/Scripts/ThirdParty/PolyTri/Triangulation/Delaunay/Sweep/DTSweep.cs:537)
WorldMapStrategyKit.Poly2Tri.DTSweep.EdgeEvent (WorldMapStrategyKit.Poly2Tri.DTSweepContext tcx, WorldMapStrategyKit.Poly2Tri.DTSweepConstraint edge, WorldMapStrategyKit.Poly2Tri.AdvancingFrontNode node) (at Assets/WorldMapStrategyKit/Scripts/ThirdParty/PolyTri/Triangulation/Delaunay/Sweep/DTSweep.cs:353)
WorldMapStrategyKit.Poly2Tri.DTSweep.Sweep (WorldMapStrategyKit.Poly2Tri.DTSweepContext tcx) (at Assets/WorldMapStrategyKit/Scripts/ThirdParty/PolyTri/Triangulation/Delaunay/Sweep/DTSweep.cs:101)
WorldMapStrategyKit.Poly2Tri.DTSweep.Triangulate (WorldMapStrategyKit.Poly2Tri.DTSweepContext tcx) (at Assets/WorldMapStrategyKit/Scripts/ThirdParty/PolyTri/Triangulation/Delaunay/Sweep/DTSweep.cs:64)
WorldMapStrategyKit.Poly2Tri.P2T.Triangulate (WorldMapStrategyKit.Poly2Tri.TriangulationContext tcx) (at Assets/WorldMapStrategyKit/Scripts/ThirdParty/PolyTri/P2T.cs:75)
WorldMapStrategyKit.Poly2Tri.P2T.Triangulate (WorldMapStrategyKit.Poly2Tri.TriangulationAlgorithm algorithm, WorldMapStrategyKit.Poly2Tri.ITriangulatable t) (at Assets/WorldMapStrategyKit/Scripts/ThirdParty/PolyTri/P2T.cs:68)
WorldMapStrategyKit.Poly2Tri.P2T.Triangulate (WorldMapStrategyKit.Poly2Tri.Polygon p) (at Assets/WorldMapStrategyKit/Scripts/ThirdParty/PolyTri/P2T.cs:44)
WorldMapStrategyKit.WMSK.GenerateCountryRegionSurface (System.Int32 countryIndex, System.Int32 regionIndex, UnityEngine.Material material, UnityEngine.Vector2 textureScale, UnityEngine.Vector2 textureOffset, System.Single textureRotation) (at Assets/WorldMapStrategyKit/Scripts/Core/Internal/WMSKPrivCountry.cs:796)
WorldMapStrategyKit.WMSK.HighlightCountryRegionSingle (System.Int32 countryIndex, System.Int32 regionIndex, System.Boolean refreshGeometry, System.Boolean drawOutline) (at Assets/WorldMapStrategyKit/Scripts/Core/Internal/WMSKPrivCountry.cs:660)
WorldMapStrategyKit.WMSK.HighlightCountryRegion (System.Int32 countryIndex, System.Int32 regionIndex, System.Boolean refreshGeometry, System.Boolean drawOutline) (at Assets/WorldMapStrategyKit/Scripts/Core/Internal/WMSKPrivCountry.cs:608)
WorldMapStrategyKit.WMSK.CheckMousePos () (at Assets/WorldMapStrategyKit/Scripts/Core/Internal/WMSKPrivate.cs:1801)
WorldMapStrategyKit.WMSK.PerformUserInteraction () (at Assets/WorldMapStrategyKit/Scripts/Core/Internal/WMSKPrivate.cs:699)
WorldMapStrategyKit.WMSK.Update () (at Assets/WorldMapStrategyKit/Scripts/Core/Internal/WMSKPrivate.cs:245)

https://www.youtube.com/watch?v=VzYHv-9sZ7Q

In the second case I change owner of the provinces No Man's Land and Teal Inlet to UK. Then I change back Teal Inlet to Argentine.
This makes No Man's Land province to disappear. At least it's not possible to interact with it anymore.

https://www.youtube.com/watch?v=HT_8EBhEhq4

Note that you won't have to try and fix these issues, I just want to explain why I won't use these methods going forward. I've come to the conclusion that these operations can probably never be 100% succesful due to all the low-level operations taking place.
For the game I'm making stability of the core features (like changing province owner) must be 100 %. So there can be no merging of regions and so on.

I will inactivate frontiers, and use the CountryTransferProvince() method instead. It's much quicker, and hopefully reliable (as far as I've tested it).
I plan to create other frontiers that are totally separate objects that are rendered on top of the world objects.

Posted by: Pollyfun
« on: August 04, 2021, 07:41:13 AM »

Update: I could easily loop through the provinces and set a property on each one. I saw there's an attrib property. Perhaps this one could be used, or a new property to mark it as ocean?
Then this property could be used for ignoring sea provinces when creating frontiers (when Coastline is unchecked).

You can skip this request. I'm trying to fix frontiers in another way. I'll give an update later.
Posted by: Kronnect
« on: August 03, 2021, 05:17:38 PM »

A region represents a continuous area of land or domain. It's represented by a polygons, which are the ones that get merged. Polygons are then triangulated to create a color or texture surface when highlighting or customizing the region.
In this case, regions are merged so a continuous polygon shows the frontiers of a country.
Posted by: Pollyfun
« on: August 03, 2021, 04:04:35 PM »

Another general question. Why are regions merged at all? Is for performance reasons (fewer separate objects to render simultaneously), and/or is it a necessity before creating frontiers?
Posted by: Pollyfun
« on: August 03, 2021, 10:51:19 AM »

Ah, okay. I got it to work in the default world map, but not in this scenario. I suspect the sea provinces are treated just as land provinces so the frontier is created anyway. Any idea for this?
Thanks

Update: I could easily loop through the provinces and set a property on each one. I saw there's an attrib property. Perhaps this one could be used, or a new property to mark it as ocean?
Then this property could be used for ignoring sea provinces when creating frontiers (when Coastline is unchecked).
Posted by: Kronnect
« on: August 03, 2021, 10:39:37 AM »

Visually speaking, yes. You have some options to hide coast lines in the inspector. See attached.
Posted by: Pollyfun
« on: August 03, 2021, 10:29:52 AM »

Ok, I understand. Later optimizations are always welcome. :)

But lets say for purely graphical reasons, would it be difficult to add a parameter to skip the creation of all coastline frontiers?
I get the impression that this scenario could look better/clearer that way.