public void InitializeFromImperator( Imperator.Provinces.Province impProvince, CultureMapper cultureMapper, ReligionMapper religionMapper ) { ImperatorProvince = impProvince; // If we're initializing this from Imperator provinces, then having an owner or being a wasteland/sea is not a given - // there are uncolonized provinces in Imperator, also uninhabitables have culture and religion. var impOwnerCountry = ImperatorProvince.OwnerCountry.Value; if (impOwnerCountry is not null) { ownerTitle = impOwnerCountry.CK3Title; // linking to our holder's title } // Religion first SetReligionFromImperator(religionMapper); // Then culture SetCultureFromImperator(cultureMapper); // Holding type SetHoldingFromImperator(); details.Buildings.Clear(); }
private static CultureInfo GetNumberCulture(TextRunProperties properties, out NumberSubstitutionMethod method, out bool ignoreUserOverride) { ignoreUserOverride = true; NumberSubstitution sub = properties.NumberSubstitution; if (sub == null) { method = NumberSubstitutionMethod.AsCulture; return(CultureMapper.GetSpecificCulture(properties.CultureInfo)); } method = sub.Substitution; switch (sub.CultureSource) { case NumberCultureSource.Text: return(CultureMapper.GetSpecificCulture(properties.CultureInfo)); case NumberCultureSource.User: ignoreUserOverride = false; return(CultureInfo.CurrentCulture); case NumberCultureSource.Override: return(sub.CultureOverride); } return(null); }
/// <summary> /// Compute a shaped glyph run object from specified glyph-based info /// </summary> internal sealed override GlyphRun ComputeShapedGlyphRun( Point origin, char[] characterString, ushort[] clusterMap, ushort[] glyphIndices, IList <double> glyphAdvances, IList <Point> glyphOffsets, bool rightToLeft, bool sideways ) { Invariant.Assert(_shapeTypeface != null); Invariant.Assert(glyphIndices != null); // Device fonts are only used through the LS non-glyphed code path. Only when a DigitCulture is set // will a potential device font be ignored and come through shaping. Invariant.Assert(_shapeTypeface.DeviceFont == null || _textItem.DigitCulture != null); bool[] caretStops = null; if (clusterMap != null && (HasExtendedCharacter || NeedsCaretInfo) ) { caretStops = new bool[clusterMap.Length + 1]; // caret stops at cluster boundaries, the first and the last entries are always set caretStops[0] = true; caretStops[clusterMap.Length] = true; ushort lastGlyph = clusterMap[0]; for (int i = 1; i < clusterMap.Length; i++) { ushort glyph = clusterMap[i]; if (glyph != lastGlyph) { caretStops[i] = true; lastGlyph = glyph; } } } return(GlyphRun.TryCreate( _shapeTypeface.GlyphTypeface, (rightToLeft ? 1 : 0), sideways, _emSize, glyphIndices, origin, glyphAdvances, glyphOffsets, characterString, null, clusterMap, caretStops, XmlLanguage.GetLanguage(CultureMapper.GetSpecificCulture(_properties.CultureInfo).IetfLanguageTag), _textFormattingMode )); }
public void ImportImperatorCharacters(Imperator.World impWorld, ReligionMapper religionMapper, CultureMapper cultureMapper, TraitMapper traitMapper, NicknameMapper nicknameMapper, LocDB locDB, ProvinceMapper provinceMapper, DeathReasonMapper deathReasonMapper, Date endDate, Date ck3BookmarkDate ) { Logger.Info("Importing Imperator Characters..."); foreach (var character in impWorld.Characters) { ImportImperatorCharacter( character, religionMapper, cultureMapper, traitMapper, nicknameMapper, locDB, provinceMapper, deathReasonMapper, endDate, ck3BookmarkDate ); } Logger.Info($"{Count} total characters recognized."); LinkMothersAndFathers(); LinkSpouses(); LinkPrisoners(); }
private void ImportImperatorCharacter( Imperator.Characters.Character character, ReligionMapper religionMapper, CultureMapper cultureMapper, TraitMapper traitMapper, NicknameMapper nicknameMapper, LocDB locDB, ProvinceMapper provinceMapper, DeathReasonMapper deathReasonMapper, Date endDate, Date ck3BookmarkDate ) { // Create a new CK3 character var newCharacter = new Character( character, religionMapper, cultureMapper, traitMapper, nicknameMapper, locDB, provinceMapper, deathReasonMapper, endDate, ck3BookmarkDate ); character.CK3Character = newCharacter; Add(newCharacter); }
/// <summary> /// Compute unshaped glyph run object from the specified character-based info /// </summary> internal sealed override GlyphRun ComputeUnshapedGlyphRun( Point origin, char[] characterString, IList <double> characterAdvances ) { bool nullFont; GlyphTypeface glyphTypeface = GetGlyphTypeface(out nullFont); Invariant.Assert(glyphTypeface != null); return(glyphTypeface.ComputeUnshapedGlyphRun( origin, new CharacterBufferRange( characterString, 0, // offsetToFirstChar characterString.Length ), characterAdvances, _emSize, (float)_properties.PixelsPerDip, _properties.FontHintingEmSize, nullFont, CultureMapper.GetSpecificCulture(_properties.CultureInfo), (_shapeTypeface == null || _shapeTypeface.DeviceFont == null) ? null : _shapeTypeface.DeviceFont.Name, _textFormattingMode )); }
private void ImportImperatorCountry( Country country, CountryCollection imperatorCountries, TagTitleMapper tagTitleMapper, LocDB locDB, ProvinceMapper provinceMapper, CoaMapper coaMapper, GovernmentMapper governmentMapper, SuccessionLawMapper successionLawMapper, DefiniteFormMapper definiteFormMapper, ReligionMapper religionMapper, CultureMapper cultureMapper, NicknameMapper nicknameMapper, CharacterCollection characters, Date conversionDate ) { // Create a new title or update existing title var name = DetermineName(country, imperatorCountries, tagTitleMapper, locDB); if (TryGetValue(name, out var existingTitle)) { existingTitle.InitializeFromTag( country, imperatorCountries, locDB, provinceMapper, coaMapper, governmentMapper, successionLawMapper, definiteFormMapper, religionMapper, cultureMapper, nicknameMapper, characters, conversionDate ); } else { Add( country, imperatorCountries, locDB, provinceMapper, coaMapper, tagTitleMapper, governmentMapper, successionLawMapper, definiteFormMapper, religionMapper, cultureMapper, nicknameMapper, characters, conversionDate ); } }
public void CultureMatchesWithReligion() { var reader = new BufferedReader( "link = { ck3 = culture imp = qwe imp = test imp = poi religion = thereligion }" ); var culMapper = new CultureMapper(reader); Assert.Equal("culture", culMapper.Match("test", "thereligion", 56, 49, "e_title")); }
public void SimpleCultureCorrectlyMatches() { var reader = new BufferedReader( "link = { ck3 = culture imp = qwe imp = test imp = poi }" ); var culMapper = new CultureMapper(reader); Assert.Equal("culture", culMapper.Match("test", "", 56, 49, "e_title")); }
public void CultureFailsWithNoReligion() { var reader = new BufferedReader( "link = { ck3 = culture imp = qwe imp = test imp = poi religion = thereligion }" ); var culMapper = new CultureMapper(reader); Assert.Null(culMapper.Match("test", "", 56, 49, "e_title")); }
public void SimpleCultureMatchesWithNonReligiousMatch() { var reader = new BufferedReader( "link = { ck3 = culture imp = test }" ); var culMapper = new CultureMapper(reader); Assert.Equal("culture", culMapper.NonReligiousMatch("test", "", 56, 49, "e_title")); }
public void CultureFailsWithWrongCapital() { var reader = new BufferedReader( "link = { ck3 = culture imp = qwe imp = test imp = poi religion = thereligion ck3Province = 4 }" ); var culMapper = new CultureMapper(reader); Assert.Null(culMapper.Match("test", "thereligion", 3, 49, "e_title")); }
public void NonMatchGivesEmptyOptional() { var reader = new BufferedReader( "link = { ck3 = culture imp = culture }" ); var culMapper = new CultureMapper(reader); Assert.Null(culMapper.Match("nonMatchingCulture", "", 56, 49, "e_title")); }
public void CultureMatchesWithOwnerTitle() { var reader = new BufferedReader( "link = { ck3 = culture imp = qwe imp = test imp = poi religion = thereligion ck3Province = 4 owner = e_roman_empire }" ); var culMapper = new CultureMapper(reader); Assert.Equal("culture", culMapper.Match("test", "thereligion", 4, 49, "e_roman_empire")); }
public void SetHoldingLogicWorks() { var reader1 = new BufferedReader(" = { province_rank=city_metropolis }"); var reader2 = new BufferedReader(" = { province_rank=city fort=yes }"); var reader3 = new BufferedReader(" = { province_rank=city }"); var reader4 = new BufferedReader(" = { province_rank=settlement holy_site = 69 fort=yes }"); var reader5 = new BufferedReader(" = { province_rank=settlement fort=yes }"); var reader6 = new BufferedReader(" = { province_rank=settlement }"); var imperatorCountry = new ImperatorToCK3.Imperator.Countries.Country(1); var impProvince = ImperatorToCK3.Imperator.Provinces.Province.Parse(reader1, 42); impProvince.LinkOwnerCountry(imperatorCountry); var impProvince2 = ImperatorToCK3.Imperator.Provinces.Province.Parse(reader2, 43); impProvince2.LinkOwnerCountry(imperatorCountry); var impProvince3 = ImperatorToCK3.Imperator.Provinces.Province.Parse(reader3, 44); impProvince3.LinkOwnerCountry(imperatorCountry); var impProvince4 = ImperatorToCK3.Imperator.Provinces.Province.Parse(reader4, 45); impProvince4.LinkOwnerCountry(imperatorCountry); var impProvince5 = ImperatorToCK3.Imperator.Provinces.Province.Parse(reader5, 46); impProvince5.LinkOwnerCountry(imperatorCountry); var impProvince6 = ImperatorToCK3.Imperator.Provinces.Province.Parse(reader6, 47); impProvince6.LinkOwnerCountry(imperatorCountry); var province1 = new Province(); var province2 = new Province(); var province3 = new Province(); var province4 = new Province(); var province5 = new Province(); var province6 = new Province(); var landedTitles = new Title.LandedTitles(); var cultureMapper = new CultureMapper(); var religionMapper = new ReligionMapper(); province1.InitializeFromImperator(impProvince, landedTitles, cultureMapper, religionMapper); province2.InitializeFromImperator(impProvince2, landedTitles, cultureMapper, religionMapper); province3.InitializeFromImperator(impProvince3, landedTitles, cultureMapper, religionMapper); province4.InitializeFromImperator(impProvince4, landedTitles, cultureMapper, religionMapper); province5.InitializeFromImperator(impProvince5, landedTitles, cultureMapper, religionMapper); province6.InitializeFromImperator(impProvince6, landedTitles, cultureMapper, religionMapper); Assert.Equal("city_holding", province1.Holding); Assert.Equal("castle_holding", province2.Holding); Assert.Equal("city_holding", province3.Holding); Assert.Equal("church_holding", province4.Holding); Assert.Equal("castle_holding", province5.Holding); Assert.Equal("none", province6.Holding); }
public void ImportImperatorCountries( CountryCollection imperatorCountries, TagTitleMapper tagTitleMapper, LocDB locDB, ProvinceMapper provinceMapper, CoaMapper coaMapper, GovernmentMapper governmentMapper, SuccessionLawMapper successionLawMapper, DefiniteFormMapper definiteFormMapper, ReligionMapper religionMapper, CultureMapper cultureMapper, NicknameMapper nicknameMapper, CharacterCollection characters, Date conversionDate ) { Logger.Info("Importing Imperator Countries..."); // landedTitles holds all titles imported from CK3. We'll now overwrite some and // add new ones from Imperator tags. var counter = 0; // We don't need pirates, barbarians etc. foreach (var country in imperatorCountries.Where(c => c.CountryType == CountryType.real)) { ImportImperatorCountry( country, imperatorCountries, tagTitleMapper, locDB, provinceMapper, coaMapper, governmentMapper, successionLawMapper, definiteFormMapper, religionMapper, cultureMapper, nicknameMapper, characters, conversionDate ); ++counter; } Logger.Info($"Imported {counter} countries from I:R."); }
public QuotesManager() { InitializeComponent(); playlist = new Playlist(); cultureMapper = new CultureMapper { new EnglishQuoteCollectorRules() }; playlistSerializer = new XmlPlaylistSerializer(playlist); if (File.Exists(QuotesDatabaseFile)) { try { playlistSerializer.LoadAsync(QuotesDatabaseFile); } catch (FileNotFoundException) { } } lookupManager = new LookupManager(playlist, cultureMapper); InitializeEventHandlers(); Loaded += QuotesManager_Loaded; }
public RulerTerm( Imperator.Countries.RulerTerm imperatorRulerTerm, Characters.CharacterCollection characters, GovernmentMapper governmentMapper, LocDB locDB, ReligionMapper religionMapper, CultureMapper cultureMapper, NicknameMapper nicknameMapper, ProvinceMapper provinceMapper ) { if (imperatorRulerTerm.CharacterId is not null) { CharacterId = $"imperator{imperatorRulerTerm.CharacterId}"; } StartDate = imperatorRulerTerm.StartDate; if (imperatorRulerTerm.Government is not null) { Government = governmentMapper.GetCK3GovernmentForImperatorGovernment(imperatorRulerTerm.Government); } PreImperatorRuler = imperatorRulerTerm.PreImperatorRuler; if (PreImperatorRuler?.Country is not null) { // create a new ruler character var character = new Character( PreImperatorRuler, StartDate, PreImperatorRuler.Country, locDB, religionMapper, cultureMapper, nicknameMapper, provinceMapper ); characters.Add(character); CharacterId = character.Id; } }
public Title Add( Country country, CountryCollection imperatorCountries, LocDB locDB, ProvinceMapper provinceMapper, CoaMapper coaMapper, TagTitleMapper tagTitleMapper, GovernmentMapper governmentMapper, SuccessionLawMapper successionLawMapper, DefiniteFormMapper definiteFormMapper, ReligionMapper religionMapper, CultureMapper cultureMapper, NicknameMapper nicknameMapper, CharacterCollection characters, Date conversionDate ) { var newTitle = new Title(this, country, imperatorCountries, locDB, provinceMapper, coaMapper, tagTitleMapper, governmentMapper, successionLawMapper, definiteFormMapper, religionMapper, cultureMapper, nicknameMapper, characters, conversionDate ); dict[newTitle.Id] = newTitle; return(newTitle); }
private Title(LandedTitles parentCollection, Country country, CountryCollection imperatorCountries, LocDB locDB, ProvinceMapper provinceMapper, CoaMapper coaMapper, TagTitleMapper tagTitleMapper, GovernmentMapper governmentMapper, SuccessionLawMapper successionLawMapper, DefiniteFormMapper definiteFormMapper, ReligionMapper religionMapper, CultureMapper cultureMapper, NicknameMapper nicknameMapper, CharacterCollection characters, Date conversionDate ) { this.parentCollection = parentCollection; Id = DetermineName(country, imperatorCountries, tagTitleMapper, locDB); SetRank(); InitializeFromTag( country, imperatorCountries, locDB, provinceMapper, coaMapper, governmentMapper, successionLawMapper, definiteFormMapper, religionMapper, cultureMapper, nicknameMapper, characters, conversionDate ); }
/// <summary> /// Get text immediately preceding cpLimit. /// </summary> internal TextSpan <CultureSpecificCharacterBufferRange> GetPrecedingText(TextSource textSource, int cpLimit) { if (cpLimit > 0) { SpanRider textRunSpanRider = new SpanRider(_textRunVector, _latestPosition); if (textRunSpanRider.At(cpLimit - 1)) { CharacterBufferRange charString = CharacterBufferRange.Empty; CultureInfo culture = null; TextRun run = textRunSpanRider.CurrentElement as TextRun; if (run != null) { // Only TextRun containing text would have non-empty Character buffer range. if (TextRunInfo.GetRunType(run) == Plsrun.Text && run.CharacterBufferReference.CharacterBuffer != null) { charString = new CharacterBufferRange( run.CharacterBufferReference, cpLimit - textRunSpanRider.CurrentSpanStart); culture = CultureMapper.GetSpecificCulture(run.Properties.CultureInfo); } return(new TextSpan <CultureSpecificCharacterBufferRange>( cpLimit - textRunSpanRider.CurrentSpanStart, // cp length new CultureSpecificCharacterBufferRange(culture, charString) )); } } } // not in cache so call back to client return(textSource.GetPrecedingText(cpLimit)); }
/// <summary> /// Break a run of text into individually shape items. /// Shape items are delimited by /// Change of writing system /// Change of glyph typeface /// </summary> IList <TextShapeableSymbols> ITextSymbols.GetTextShapeableSymbols( GlyphingCache glyphingCache, CharacterBufferReference characterBufferReference, int length, bool rightToLeft, bool isRightToLeftParagraph, CultureInfo digitCulture, TextModifierScope textModifierScope, TextFormattingMode textFormattingMode, bool isSideways ) { if (characterBufferReference.CharacterBuffer == null) { throw new ArgumentNullException("characterBufferReference.CharacterBuffer"); } int offsetToFirstChar = characterBufferReference.OffsetToFirstChar - _characterBufferReference.OffsetToFirstChar; Debug.Assert(characterBufferReference.CharacterBuffer == _characterBufferReference.CharacterBuffer); Debug.Assert(offsetToFirstChar >= 0 && offsetToFirstChar < _length); if (length < 0 || offsetToFirstChar + length > _length) { length = _length - offsetToFirstChar; } // Get the actual text run properties in effect, after invoking any // text modifiers that may be in scope. TextRunProperties textRunProperties = _textRunProperties; if (textModifierScope != null) { textRunProperties = textModifierScope.ModifyProperties(textRunProperties); } if (!rightToLeft) { // Fast loop early out for run with all non-complex characters // which can be optimized by not going thru shaping engine. int nominalLength; if (textRunProperties.Typeface.CheckFastPathNominalGlyphs( new CharacterBufferRange(characterBufferReference, length), textRunProperties.FontRenderingEmSize, (float)textRunProperties.PixelsPerDip, 1.0, double.MaxValue, // widthMax true, // keepAWord digitCulture != null, CultureMapper.GetSpecificCulture(textRunProperties.CultureInfo), textFormattingMode, isSideways, false, //breakOnTabs out nominalLength ) && length == nominalLength) { return(new TextShapeableCharacters[] { new TextShapeableCharacters( new CharacterBufferRange(characterBufferReference, nominalLength), textRunProperties, textRunProperties.FontRenderingEmSize, new MS.Internal.Text.TextInterface.ItemProps(), null, // shapeTypeface (no shaping required) false, // nullShape, textFormattingMode, isSideways ) }); } } IList <TextShapeableSymbols> shapeables = new List <TextShapeableSymbols>(2); glyphingCache.GetShapeableText( textRunProperties.Typeface, characterBufferReference, length, textRunProperties, digitCulture, isRightToLeftParagraph, shapeables, this as IShapeableTextCollector, textFormattingMode ); return(shapeables); }
public void ImportImperatorProvinces(Imperator.World impWorld, Title.LandedTitles titles, CultureMapper cultureMapper, ReligionMapper religionMapper, ProvinceMapper provinceMapper) { Logger.Info("Importing Imperator Provinces..."); var counter = 0; // Imperator provinces map to a subset of CK3 provinces. We'll only rewrite those we are responsible for. foreach (var province in this) { var impProvinces = provinceMapper.GetImperatorProvinceNumbers(province.Id); // Provinces we're not affecting will not be in this list. if (impProvinces.Count == 0) { continue; } // Next, we find what province to use as its initializing source. var sourceProvince = DetermineProvinceSource(impProvinces, impWorld); if (sourceProvince is null) { Logger.Warn($"Could not determine source province for CK3 province {province.Id}!"); continue; // MISMAP, or simply have mod provinces loaded we're not using. } province.InitializeFromImperator(sourceProvince.Value.Value, titles, cultureMapper, religionMapper); // And finally, initialize it. ++counter; } Logger.Info($"{impWorld.Provinces.Count} Imperator provinces imported into {counter} CK3 provinces."); }
/// <summary> /// Fetch cached textrun /// </summary> internal TextRun FetchTextRun( FormatSettings settings, int cpFetch, int cpFirst, out int offsetToFirstCp, out int runLength ) { SpanRider textRunSpanRider = new SpanRider(_textRunVector, _latestPosition, cpFetch); _latestPosition = textRunSpanRider.SpanPosition; TextRun textRun = (TextRun)textRunSpanRider.CurrentElement; if (textRun == null) { // run not already cached, fetch new run and cache it textRun = settings.TextSource.GetTextRun(cpFetch); if (textRun.Length < 1) { throw new ArgumentOutOfRangeException("textRun.Length", SR.Get(SRID.ParameterMustBeGreaterThanZero)); } Plsrun plsrun = TextRunInfo.GetRunType(textRun); if (plsrun == Plsrun.Text || plsrun == Plsrun.InlineObject) { TextRunProperties properties = textRun.Properties; if (properties == null) { throw new ArgumentException(SR.Get(SRID.TextRunPropertiesCannotBeNull)); } if (properties.FontRenderingEmSize <= 0) { throw new ArgumentException(SR.Get(SRID.PropertyOfClassMustBeGreaterThanZero, "FontRenderingEmSize", "TextRunProperties")); } double realMaxFontRenderingEmSize = Constants.RealInfiniteWidth / Constants.GreatestMutiplierOfEm; if (properties.FontRenderingEmSize > realMaxFontRenderingEmSize) { throw new ArgumentException(SR.Get(SRID.PropertyOfClassCannotBeGreaterThan, "FontRenderingEmSize", "TextRunProperties", realMaxFontRenderingEmSize)); } CultureInfo culture = CultureMapper.GetSpecificCulture(properties.CultureInfo); if (culture == null) { throw new ArgumentException(SR.Get(SRID.PropertyOfClassCannotBeNull, "CultureInfo", "TextRunProperties")); } if (properties.Typeface == null) { throw new ArgumentException(SR.Get(SRID.PropertyOfClassCannotBeNull, "Typeface", "TextRunProperties")); } } // // TextRun is specifial to SpanVector because TextRun also encodes position which needs to be // consistent with the positions encoded by SpanVector. In run cache, the begining of a span // should always correspond to the begining of a cached text run. If the end of the currently fetched // run overlaps with the begining of an already cached run, the begining of the cached run needs to be // adjusted as well as its span. Because we can't gurantee the correctness of the overlapped range // so we'll simply remove the overlapped runs here. // // Move the rider to the end of the current run textRunSpanRider.At(cpFetch + textRun.Length - 1); _latestPosition = textRunSpanRider.SpanPosition; if (textRunSpanRider.CurrentElement != _textRunVector.Default) { // The end overlaps with one or more cached runs, clear the range from the // begining of the current fetched run to the end of the last overlapped cached run. _latestPosition = _textRunVector.SetReference( cpFetch, textRunSpanRider.CurrentPosition + textRunSpanRider.Length - cpFetch, _textRunVector.Default, _latestPosition ); } _latestPosition = _textRunVector.SetReference(cpFetch, textRun.Length, textRun, _latestPosition); // Refresh the rider's SpanPosition following previous SpanVector.SetReference calls textRunSpanRider.At(_latestPosition, cpFetch); } // If the TextRun was obtained from the cache, make sure it has the right PixelsPerDip set on its properties. if (textRun.Properties != null) { textRun.Properties.PixelsPerDip = settings.TextSource.PixelsPerDip; } offsetToFirstCp = textRunSpanRider.CurrentPosition - textRunSpanRider.CurrentSpanStart; runLength = textRunSpanRider.Length; Debug.Assert(textRun != null && runLength > 0, "Invalid run!"); bool isText = textRun is ITextSymbols; if (isText) { // Chop text run to optimal length so we dont spend forever analysing // them all at once. int looseCharLength = TextStore.TypicalCharactersPerLine - cpFetch + cpFirst; if (looseCharLength <= 0) { // this line already exceeds typical line length, incremental fetch goes // about a quarter of the typical length. looseCharLength = (int)Math.Round(TextStore.TypicalCharactersPerLine * 0.25); } if (runLength > looseCharLength) { if (TextRunInfo.GetRunType(textRun) == Plsrun.Text) { // // When chopping the run at the typical line length, // - don't chop in between of higher & lower surrogate // - don't chop combining mark away from its base character // - don't chop joiner from surrounding characters // // Starting from the initial chopping point, we look ahead to find a safe position. We stop at // a limit in case the run consists of many combining mark & joiner. That is rare and doesn't make // much sense in shaping already. // CharacterBufferReference charBufferRef = textRun.CharacterBufferReference; // We look ahead by one more line at most. It is not normal to have // so many combining mark or joiner characters in a row. It doesn't make sense to // look further if so. int lookAheadLimit = Math.Min(runLength, looseCharLength + TextStore.TypicalCharactersPerLine); int sizeOfChar = 0; int endOffset = 0; bool canBreakAfterPrecedingChar = false; for (endOffset = looseCharLength - 1; endOffset < lookAheadLimit; endOffset += sizeOfChar) { CharacterBufferRange charString = new CharacterBufferRange( charBufferRef.CharacterBuffer, charBufferRef.OffsetToFirstChar + offsetToFirstCp + endOffset, runLength - endOffset ); int ch = Classification.UnicodeScalar(charString, out sizeOfChar); // We can only safely break if the preceding char is not a joiner character (i.e. can-break-after), // and the current char is not combining or joiner (i.e. can-break-before). if (canBreakAfterPrecedingChar && !Classification.IsCombining(ch) && !Classification.IsJoiner(ch)) { break; } canBreakAfterPrecedingChar = !Classification.IsJoiner(ch); } looseCharLength = Math.Min(runLength, endOffset); } runLength = looseCharLength; } } Debug.Assert( // valid run found runLength > 0 // non-text run always fetched at run start && (isText || textRunSpanRider.CurrentSpanStart - textRunSpanRider.CurrentPosition == 0) // span rider of both text and format point to valid position && (textRunSpanRider.Length > 0 && textRunSpanRider.CurrentElement != null), "Text run fetching error!" ); return(textRun); }
public void InitializeFromTag( Country country, CountryCollection imperatorCountries, LocDB locDB, ProvinceMapper provinceMapper, CoaMapper coaMapper, GovernmentMapper governmentMapper, SuccessionLawMapper successionLawMapper, DefiniteFormMapper definiteFormMapper, ReligionMapper religionMapper, CultureMapper cultureMapper, NicknameMapper nicknameMapper, CharacterCollection characters, Date conversionDate ) { IsImportedOrUpdatedFromImperator = true; ImperatorCountry = country; ImperatorCountry.CK3Title = this; LocBlock?validatedName = GetValidatedName(country, imperatorCountries, locDB); HasDefiniteForm.Value = definiteFormMapper.IsDefiniteForm(ImperatorCountry.Name); RulerUsesTitleName.Value = false; PlayerCountry = ImperatorCountry.PlayerCountry; ClearHolderSpecificHistory(); FillHolderAndGovernmentHistory(); // ------------------ determine color var color1Opt = ImperatorCountry.Color1; if (color1Opt is not null) { Color1 = color1Opt; } var color2Opt = ImperatorCountry.Color2; if (color2Opt is not null) { Color2 = color2Opt; } // determine successions laws history.InternalHistory.AddFieldValue("succession_laws", successionLawMapper.GetCK3LawsForImperatorLaws(ImperatorCountry.GetLaws()), conversionDate, "succession_laws" ); // determine CoA CoA = coaMapper.GetCoaForFlagName(ImperatorCountry.Flag); // determine other attributes var srcCapital = ImperatorCountry.Capital; if (srcCapital is not null) { var provMappingsForImperatorCapital = provinceMapper.GetCK3ProvinceNumbers((ulong)srcCapital); if (provMappingsForImperatorCapital.Count > 0) { var foundCounty = parentCollection.GetCountyForProvince(provMappingsForImperatorCapital[0]); if (foundCounty is not null) { CapitalCounty = foundCounty; } } } // determine country name localization var nameSet = false; if (validatedName is not null) { var nameLocBlock = Localizations.AddLocBlock(Id); nameLocBlock.CopyFrom(validatedName); nameSet = true; } if (!nameSet) { var impTagLoc = locDB.GetLocBlockForKey(ImperatorCountry.Tag); if (impTagLoc is not null) { var nameLocBlock = Localizations.AddLocBlock(Id); nameLocBlock.CopyFrom(impTagLoc); nameSet = true; } } if (!nameSet) { // use unlocalized name if not empty var name = ImperatorCountry.Name; if (!string.IsNullOrEmpty(name)) { Logger.Warn($"Using unlocalized Imperator name {name} as name for {Id}!"); var nameLocBlock = Localizations.AddLocBlock(Id); nameLocBlock["english"] = name; nameLocBlock.FillMissingLocWithBaseLanguageLoc(); nameSet = true; } } // giving up if (!nameSet) { Logger.Warn($"{Id} needs help with localization! {ImperatorCountry.Name}?"); } // determine adjective localization TrySetAdjectiveLoc(locDB, imperatorCountries); void FillHolderAndGovernmentHistory() { // ------------------ determine previous and current holders // there was no 0 AD, but year 0 works in game and serves well for adding BC characters to holder history var firstPossibleDate = new Date(0, 1, 1); foreach (var impRulerTerm in ImperatorCountry.RulerTerms) { var rulerTerm = new RulerTerm( impRulerTerm, characters, governmentMapper, locDB, religionMapper, cultureMapper, nicknameMapper, provinceMapper ); var characterId = rulerTerm.CharacterId; var gov = rulerTerm.Government; var startDate = new Date(rulerTerm.StartDate); if (startDate < firstPossibleDate) { startDate = new Date(firstPossibleDate); // TODO: remove this workaround if CK3 supports negative dates firstPossibleDate.ChangeByDays(1); } history.InternalHistory.AddFieldValue("holder", characterId, startDate, "holder"); if (gov is not null) { history.InternalHistory.AddFieldValue("government", gov, startDate, "government"); } } if (ImperatorCountry.Government is not null) { var lastCK3TermGov = history.GetGovernment(conversionDate); var ck3CountryGov = governmentMapper.GetCK3GovernmentForImperatorGovernment(ImperatorCountry.Government); if (lastCK3TermGov != ck3CountryGov && ck3CountryGov is not null) { history.InternalHistory.AddFieldValue("government", ck3CountryGov, conversionDate, "government"); } } } }