public static async Task EntryAsync(MainRepository repo, string ipAddress, Character newChara, CharacterIcon newIcon, string password, Country newCountry, string invitationCode, bool isFreeCountry) { var town = await repo.Town.GetByIdAsync(newChara.TownId).GetOrErrorAsync(ErrorCode.TownNotFoundError); var system = await repo.System.GetAsync(); CheckEntryStatus(system.GameDateTime, ipAddress, newChara, password, newIcon, town, newCountry, isFreeCountry); // 文字数チェックしてからエスケープ newChara.Name = HtmlUtil.Escape(newChara.Name); newCountry.Name = HtmlUtil.Escape(newCountry.Name); newChara.Message = HtmlUtil.Escape(newChara.Message); // 既存との重複チェック if (await repo.Character.IsAlreadyExistsAsync(newChara.Name, newChara.AliasId)) { ErrorCode.DuplicateCharacterNameOrAliasIdError.Throw(); } if ((system.IsDebug && (await repo.System.GetDebugDataAsync()).IsCheckDuplicateEntry || !system.IsDebug) && await repo.EntryHost.ExistsAsync(ipAddress)) { ErrorCode.DuplicateEntryError.Throw(); } // 招待コードチェック Optional <InvitationCode> invitationCodeOptional = default; if (system.InvitationCodeRequestedAtEntry) { invitationCodeOptional = await repo.InvitationCode.GetByCodeAsync(invitationCode); if (!invitationCodeOptional.HasData || invitationCodeOptional.Data.HasUsed || invitationCodeOptional.Data.Aim != InvitationCodeAim.Entry) { ErrorCode.InvitationCodeRequestedError.Throw(); } } var updateCountriesRequested = false; MapLog maplog = null; var chara = new Character { Name = newChara.Name, AliasId = newChara.AliasId, Strong = newChara.Strong, StrongEx = 0, Intellect = newChara.Intellect, IntellectEx = 0, Leadership = newChara.Leadership, LeadershipEx = 0, Popularity = newChara.Popularity, PopularityEx = 0, Contribution = 0, Class = 0, DeleteTurn = (short)(Config.DeleteTurns - 10), LastUpdated = DateTime.Now, LastUpdatedGameDate = system.GameDateTime, Message = newChara.Message, Money = 10_0000 + Math.Max(system.GameDateTime.ToInt() - (Config.StartYear + Config.UpdateStartYear + 4) * 12 - Config.StartMonth, 0) * 800, Rice = 5_0000 + Math.Max(system.GameDateTime.ToInt() - (Config.StartYear + Config.UpdateStartYear + 4) * 12 - Config.StartMonth, 0) * 400, SkillPoint = Math.Max(0, (int)((system.IntGameDateTime - Config.UpdateStartYear * 12) * 0.8f)), SoldierType = SoldierType.Common, SoldierNumber = 0, Proficiency = 0, TownId = newChara.TownId, From = newChara.From, Religion = ReligionType.Any, FormationType = newChara.FormationType, IsBeginner = newChara.IsBeginner, }; chara.SetPassword(password); // 出身 var skills = new List <CharacterSkillType>(); var items = new List <CharacterItemType>(); if (chara.From == CharacterFrom.Warrior) { skills.Add(CharacterSkillType.Strong1); chara.Strong += 20; } else if (chara.From == CharacterFrom.Civilian) { skills.Add(CharacterSkillType.Intellect1); chara.Intellect += 20; } else if (chara.From == CharacterFrom.Merchant) { skills.Add(CharacterSkillType.Merchant1); chara.Money += 200000; } else if (chara.From == CharacterFrom.Engineer) { skills.Add(CharacterSkillType.Engineer1); chara.Strong += 10; chara.Money += 100000; } else if (chara.From == CharacterFrom.Terrorist) { skills.Add(CharacterSkillType.Terrorist1); chara.Strong += 15; chara.Leadership += 5; } else if (chara.From == CharacterFrom.People) { skills.Add(CharacterSkillType.People1); chara.Popularity += 20; } else if (chara.From == CharacterFrom.Tactician) { skills.Add(CharacterSkillType.Tactician1); chara.Strong += 5; chara.Leadership += 15; } else if (chara.From == CharacterFrom.Scholar) { skills.Add(CharacterSkillType.Scholar1); chara.Intellect += 20; } else if (chara.From == CharacterFrom.Staff) { skills.Add(CharacterSkillType.Staff1); chara.Intellect += 20; } else if (chara.From == CharacterFrom.Buddhism) { if (system.RuleSet == GameRuleSet.SimpleBattle) { ErrorCode.RuleSetError.Throw(); } skills.Add(CharacterSkillType.Buddhism1); chara.Intellect += 15; chara.Religion = ReligionType.Buddhism; } else if (chara.From == CharacterFrom.Confucianism) { if (system.RuleSet == GameRuleSet.SimpleBattle) { ErrorCode.RuleSetError.Throw(); } skills.Add(CharacterSkillType.Confucianism1); chara.Intellect += 15; chara.Religion = ReligionType.Confucianism; } else if (chara.From == CharacterFrom.Taoism) { if (system.RuleSet == GameRuleSet.SimpleBattle) { ErrorCode.RuleSetError.Throw(); } skills.Add(CharacterSkillType.Taoism1); chara.Intellect += 15; chara.Religion = ReligionType.Taoism; } else { ErrorCode.InvalidParameterError.Throw(); } // 来月の更新がまだ終わってないタイミングで登録したときの、武将更新時刻の調整 if (chara.LastUpdated - system.CurrentMonthStartDateTime > TimeSpan.FromSeconds(Config.UpdateTime)) { chara.IntLastUpdatedGameDate++; } if (isFreeCountry) { // 無所属で開始 chara.CountryId = 0; await repo.Character.AddAsync(chara); maplog = new MapLog { Date = DateTime.Now, ApiGameDateTime = system.GameDateTime, EventType = EventType.CharacterEntryToFree, IsImportant = false, Message = $"<character>{chara.Name}</character> が無所属に出現しました", }; await repo.MapLog.AddAsync(maplog); } else if (town.CountryId > 0) { // 武将総数チェック var country = await repo.Country.GetByIdAsync(town.CountryId).GetOrErrorAsync(ErrorCode.CountryNotFoundError); if (country.IntEstablished + Config.CountryBattleStopDuring > system.GameDateTime.ToInt()) { var countryCharaCount = await repo.Country.CountCharactersAsync(country.Id, true); if (countryCharaCount >= Config.CountryJoinMaxOnLimited) { ErrorCode.CantJoinAtSuchCountryhError.Throw(); } else if (countryCharaCount + 1 == Config.CountryJoinMaxOnLimited) { updateCountriesRequested = true; } } // AI国家チェック if (country.AiType != CountryAiType.Human) { ErrorCode.CantJoinAtSuchCountryhError.Throw(); } // 金と米を仕官先国の武将の平均にあわせる if (system.GameDateTime.Year >= Config.UpdateStartYear + Config.CountryBattleStopDuring / 12) { var countryCharacters = (await repo.Country.GetCharactersAsync(town.CountryId)).Where(c => c.AiType == CharacterAiType.Human || c.AiType == CharacterAiType.Administrator); if (countryCharacters.Any()) { chara.Money = Math.Min((int)countryCharacters.Average(c => c.Money) + 10_0000, chara.Money); chara.Rice = Math.Min((int)countryCharacters.Average(c => c.Rice) + 5_0000, chara.Rice); } } chara.CountryId = town.CountryId; await repo.Character.AddAsync(chara); maplog = new MapLog { Date = DateTime.Now, ApiGameDateTime = system.GameDateTime, EventType = EventType.CharacterEntry, IsImportant = false, Message = $"<character>{chara.Name}</character> が <country>{country.Name}</country> に仕官しました", }; await repo.MapLog.AddAsync(maplog); } else { // 重複チェック if ((await repo.Country.GetAllAsync()).Any(c => c.Name == newCountry.Name || c.CountryColorId == newCountry.CountryColorId)) { ErrorCode.DuplicateCountryNameOrColorError.Throw(); } if (system.RuleSet == GameRuleSet.SimpleBattle) { newCountry.Civilization = CountryCivilization.None; } var country = new Country { Name = newCountry.Name, CountryColorId = newCountry.CountryColorId, CapitalTownId = newChara.TownId, IntEstablished = Math.Max(system.GameDateTime.ToInt(), new GameDateTime { Year = Config.UpdateStartYear, Month = 1, }.ToInt()), HasOverthrown = false, IntOverthrownGameDate = 0, LastMoneyIncomes = 0, LastRiceIncomes = 0, PolicyPoint = 10000, Religion = RandomService.Next(new ReligionType[] { ReligionType.Buddhism, ReligionType.Confucianism, ReligionType.Taoism, }), Civilization = newCountry.Civilization, }; updateCountriesRequested = true; await repo.Country.AddAsync(country); var countries = await repo.Country.GetAllAsync(); var point = 500; if (system.RuleSet != GameRuleSet.Wandering) { // 大都市に変更 town.SubType = town.Type; MapService.UpdateTownType(town, TownType.Large); // 首都の宗教 if (system.RuleSet != GameRuleSet.SimpleBattle) { if (country.Religion == ReligionType.Buddhism) { town.Buddhism += point; town.Confucianism = Math.Min(town.Confucianism, 999); town.Taoism = Math.Min(town.Taoism, 999); } if (country.Religion == ReligionType.Confucianism) { town.Confucianism += point; town.Buddhism = Math.Min(town.Buddhism, 999); town.Taoism = Math.Min(town.Taoism, 999); } if (country.Religion == ReligionType.Taoism) { town.Taoism += point; town.Buddhism = Math.Min(town.Buddhism, 999); town.Confucianism = Math.Min(town.Confucianism, 999); } } } else { country.CapitalTownId = 0; items.Add(CharacterItemType.CastleBlueprint); items.Add(CharacterItemType.CastleBlueprint); items.Add(CharacterItemType.CastleBlueprint); chara.Money += 50_0000 * 3; } await repo.SaveChangesAsync(); chara.CountryId = country.Id; if (system.RuleSet != GameRuleSet.Wandering) { town.CountryId = country.Id; } await repo.Character.AddAsync(chara); await repo.SaveChangesAsync(); var countryPost = new CountryPost { Type = CountryPostType.Monarch, CountryId = country.Id, CharacterId = chara.Id, }; await repo.Country.AddPostAsync(countryPost); if (system.RuleSet == GameRuleSet.Wandering) { maplog = new MapLog { Date = DateTime.Now, ApiGameDateTime = system.GameDateTime, EventType = EventType.StartWandering, IsImportant = true, Message = $"<character>{chara.Name}</character> は <country>{country.Name}</country> の頭領となり放浪を開始しました", }; } else { maplog = new MapLog { Date = DateTime.Now, ApiGameDateTime = system.GameDateTime, EventType = EventType.Publish, IsImportant = true, Message = $"<character>{chara.Name}</character> が <town>{town.Name}</town> に <country>{country.Name}</country> を建国しました", }; } await repo.MapLog.AddAsync(maplog); } await repo.SaveChangesAsync(); // 陣形 var formation = new Formation { CharacterId = chara.Id, Type = chara.FormationType, Level = 1, }; await repo.Character.AddFormationAsync(formation); if (invitationCodeOptional.HasData) { var code = invitationCodeOptional.Data; code.HasUsed = true; code.Used = DateTime.Now; code.CharacterId = chara.Id; } var icon = new CharacterIcon { Type = newIcon.Type, IsAvailable = true, IsMain = true, FileName = newIcon.FileName, CharacterId = chara.Id, }; await repo.Character.AddCharacterIconAsync(icon); var host = new EntryHost { CharacterId = chara.Id, IpAddress = ipAddress, }; await repo.EntryHost.AddAsync(host); var skillItems = skills.Select(s => new CharacterSkill { CharacterId = chara.Id, Type = s, Status = CharacterSkillStatus.Available, }); foreach (var si in skillItems) { await SkillService.SetCharacterAndSaveAsync(repo, si, chara); } var itemData = items.Select(i => new CharacterItem { Type = i, CharacterId = chara.Id, Status = CharacterItemStatus.CharacterHold, }); foreach (var id in itemData) { await ItemService.GenerateItemAndSaveAsync(repo, id); } await repo.SaveChangesAsync(); if (updateCountriesRequested) { var countries = await repo.Country.GetAllForAnonymousAsync(); await AnonymousStreaming.Default.SendAllAsync(countries.Select(c => ApiData.From(c))); await StatusStreaming.Default.SendAllAsync(countries.Select(c => ApiData.From(c))); } var townData = ApiData.From(new TownForAnonymous(town)); var maplogData = ApiData.From(maplog); await AnonymousStreaming.Default.SendAllAsync(maplogData); await StatusStreaming.Default.SendAllAsync(maplogData); await AnonymousStreaming.Default.SendAllAsync(townData); await StatusStreaming.Default.SendAllAsync(townData); await StatusStreaming.Default.SendCountryAsync(ApiData.From(town), town.CountryId); await CharacterService.StreamCharacterAsync(repo, chara); }
public static async Task RemoveAsync(MainRepository repo, Character character) { var unitData = await repo.Unit.GetByMemberIdAsync(character.Id); if (unitData.Unit.HasData && unitData.Member.HasData) { if (unitData.Member.Data.Post == UnitMemberPostType.Leader) { await UnitService.RemoveAsync(repo, unitData.Unit.Data.Id); } else { UnitService.Leave(repo, character.Id); } } var countryPosts = (await repo.Country.GetCharacterPostsAsync(character.Id)).ToArray(); if (countryPosts.Any()) { foreach (var post in countryPosts) { repo.Country.RemoveCharacterPost(post); } } var items = await repo.Character.GetItemsAsync(character.Id); foreach (var item in items) { var flag = false; var info = item.GetInfo(); if (info.HasData) { if (info.Data.IsUniqueCharacter) { // 一部のアイテムは放置削除と同時に消える await ItemService.SpendCharacterAsync(repo, item, character, isWithEffect : false); flag = true; } } if (!flag) { await ItemService.ReleaseCharacterAsync(repo, item, character); } } // 武将に関連付けられた都市を削除 if ((await repo.System.GetAsync()).RuleSet != GameRuleSet.SimpleBattle) { var towns = await repo.Town.GetAllAsync(); foreach (var town in towns.Where(t => t.UniqueCharacterId == character.Id)) { var charas = await repo.Town.GetCharactersAsync(town.Id); foreach (var townChara in charas) { await ChangeTownAsync(repo, RandomService.Next(towns.Where(t => t.UniqueCharacterId != character.Id)).Id, townChara); } await repo.Town.RemoveTownDefendersAsync(town.Id); repo.Town.Remove(town); town.Type = TownType.Removed; await StatusStreaming.Default.SendAllAsync(ApiData.From(town)); await AnonymousStreaming.Default.SendAllAsync(ApiData.From(town)); await LogService.AddMapLogAsync(repo, true, EventType.TownRemoved, $"<character>{character.Name}</character> の建設した <town>{town.Name}</town> は消滅しました"); if (!towns.Any(t => t.CountryId == town.CountryId && t.Type != TownType.Removed)) { var countryOptional = await repo.Country.GetAliveByIdAsync(town.CountryId); if (countryOptional.HasData) { await CountryService.OverThrowAsync(repo, countryOptional.Data, null); } } } } var ais = await repo.Character.GetManagementByHolderCharacterIdAsync(character.Id); foreach (var ai in ais) { var aiChara = await repo.Character.GetByIdAsync(ai.CharacterId); if (aiChara.HasData && !aiChara.Data.HasRemoved) { aiChara.Data.DeleteTurn = (short)Config.DeleteTurns; } repo.Character.RemoveManagement(ai); } if (character.AiType == CharacterAiType.FlyingColumn) { var management = await repo.Character.GetManagementByAiCharacterIdAsync(character.Id); if (management.HasData) { repo.Character.RemoveManagement(management.Data); } } repo.ScoutedTown.RemoveCharacter(character.Id); repo.Town.RemoveDefender(character.Id); repo.EntryHost.RemoveCharacter(character.Id); repo.PushNotificationKey.RemoveByCharacterId(character.Id); repo.Mute.RemoveCharacter(character.Id); await repo.AuthenticationData.RemoveCharacterAsync(character.Id); character.PasswordHash = character.AliasId; character.AliasId = "RM"; // 新規登録で4文字未満のIDは登録できない character.HasRemoved = true; }
private static async Task UploadImageAsync(ChatMessage message) { if (isUploadingImage || message.ImageBase64.Length > 10_000_000) { throw new Exception(); } isUploadingImage = true; byte[] binary = null; if (message.ImageBase64.StartsWith("http://") || message.ImageBase64.StartsWith("https://")) { using (var http = new HttpClient()) { binary = await http.GetByteArrayAsync(message.ImageBase64); } } else if (message.ImageBase64.StartsWith("data:image")) { // data:image/png;base64,iVB var strs = new string[] { "data:image/png;base64,", "data:image/jpg;base64,", "data:image/jpeg;base64,", "data:image/gif;base64,", "data:image/bmp;base64,", }; foreach (var str in strs) { if (message.ImageBase64.StartsWith(str)) { message.ImageBase64 = message.ImageBase64.Substring(str.Length); binary = Convert.FromBase64String(message.ImageBase64); break; } } } else { binary = Convert.FromBase64String(message.ImageBase64); } var imageKey = RandomService.Next(1, 65535); var saveFileName = Config.Game.UploadedIconDirectory + $"c_{message.Id}_{imageKey}.png"; try { using (Image <Rgba32> image = binary != null ? Image.Load(binary) : Image.Load(message.ImageBase64)) { var width = image.Width; var height = image.Height; var isResize = false; if (width > 1200) { height = (int)(height * ((float)1200 / width)); width = 1200; isResize = true; } if (height > 1200) { width = (int)(width * ((float)1200 / height)); height = 1200; isResize = true; } if (isResize) { image.Mutate(x => { x.Resize(width, height); }); } using (var stream = new FileStream(saveFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite)) { var encoder = new SixLabors.ImageSharp.Formats.Png.PngEncoder(); image.Save(stream, encoder); } } message.ImageKey = imageKey; Task.Run(() => { Task.Delay(10_000).Wait(); isUploadingImage = false; }); } catch (Exception ex) { message.ImageKey = 0; Task.Run(() => { Task.Delay(10_000).Wait(); isUploadingImage = false; }); throw ex; } }
public static async Task ResetAsync(MainRepository repo) { var now = DateTime.Now; var system = await repo.System.GetAsync(); var history = await repo.History.GetAsync(system.Period, system.BetaVersion); if (history.HasData) { var countries = await repo.Country.GetAllAsync(); var messages = await repo.ChatMessage.GetAllAsync(); history.Data.ChatMessages = messages.Select(m => HistoricalChatMessage.FromChatMessage(m)).ToArray(); await repo.History.RecordChatMessagesAndSaveAsync(history.Data); var unifiedCountry = countries.FirstOrDefault(c => !c.HasOverthrown); CountryMessage unifiedCountryMessage = null; if (unifiedCountry != null) { var msgs = await repo.Country.GetMessagesAsync(CountryMessageType.Unified); unifiedCountryMessage = msgs.FirstOrDefault(); } if (unifiedCountryMessage != null) { history.Data.UnifiedCountryMessage = unifiedCountryMessage.Message; } } await OnlineService.ResetAsync(); await repo.AuthenticationData.ResetAsync(); await repo.BattleLog.ResetAsync(); await repo.CharacterItem.ResetAsync(); await repo.CharacterCommand.ResetAsync(); await repo.Character.ResetAsync(); await repo.EntryHost.ResetAsync(); await repo.ChatMessage.ResetAsync(); await repo.CountryDiplomacies.ResetAsync(); await repo.AiCountry.ResetAsync(); await repo.AiActionHistory.ResetAsync(); await repo.Country.ResetAsync(); await repo.MapLog.ResetAsync(); await repo.ScoutedTown.ResetAsync(); await repo.ThreadBbs.ResetAsync(); await repo.Town.ResetAsync(); await repo.Unit.ResetAsync(); await repo.Reinforcement.ResetAsync(); await repo.DelayEffect.ResetAsync(); await repo.Mute.ResetAsync(); // await repo.PushNotificationKey.ResetAsync(); await repo.BlockAction.ResetAsync(); // ファイル削除 try { foreach (var file in System.IO.Directory.GetFiles(Config.Game.UploadedIconDirectory).Where(f => !f.EndsWith(".txt", StringComparison.Ordinal))) { System.IO.File.Delete(file); } } catch { // Loggerがない! } await ResetTownsAndSaveAsync(repo, system.RuleSetNextPeriod); system.GameDateTime = new GameDateTime { Year = Config.StartYear, Month = Config.StartMonth, }; system.CurrentMonthStartDateTime = new DateTime(now.Year, now.Month, now.Day, 20, 0, 0, 0); system.IsWaitingReset = false; system.IntResetGameDateTime = 0; system.TerroristCount = 0; system.ManagementCountryCount = 0; system.IsBattleRoyaleMode = false; system.RuleSet = system.RuleSetNextPeriod; system.RuleSetNextPeriod = system.RuleSetAfterNextPeriod; system.IsSoftStoped = false; if (system.BetaVersion == 0 && (system.Period + 3) % 6 == 0) { system.RuleSetAfterNextPeriod = RandomService.Next(new GameRuleSet[] { GameRuleSet.SimpleBattle, GameRuleSet.Wandering, GameRuleSet.BattleRoyale, GameRuleSet.Gyokuji, GameRuleSet.Religion, }); } else { system.RuleSetAfterNextPeriod = GameRuleSet.Normal; } if (system.IsNextPeriodBeta) { system.BetaVersion++; } else { system.BetaVersion = 0; system.Period++; } if (Config.Game.IsGenerateAdminCharacter) { var admin = new Character { Name = Config.Admin.Name, AiType = CharacterAiType.Administrator, LastUpdated = DateTime.Now, LastUpdatedGameDate = system.GameDateTime, TownId = (await repo.Town.GetAllAsync()).First().Id, AliasId = Config.Admin.AliasId, Money = 1000_0000, }; admin.SetPassword(Config.Admin.Password); await repo.Character.AddAsync(admin); await repo.SaveChangesAsync(); var adminIcon = new CharacterIcon { CharacterId = admin.Id, IsAvailable = true, IsMain = true, Type = CharacterIconType.Gravatar, FileName = Config.Admin.GravatarMailAddressMD5, }; await repo.Character.AddCharacterIconAsync(adminIcon); } var ruleSetName = system.RuleSet == GameRuleSet.Normal ? "標準" : system.RuleSet == GameRuleSet.Wandering ? "放浪" : system.RuleSet == GameRuleSet.SimpleBattle ? "原理" : system.RuleSet == GameRuleSet.BattleRoyale ? "全国戦争" : system.RuleSet == GameRuleSet.Gyokuji ? "玉璽" : system.RuleSet == GameRuleSet.Religion ? "宗教" : ""; await repo.MapLog.AddAsync(new MapLog { EventType = EventType.Reset, Date = DateTime.Now, ApiGameDateTime = system.GameDateTime, IsImportant = true, Message = $"ゲームプログラムを開始しました。今期のルールセットは {ruleSetName} です", }); await repo.SaveChangesAsync(); await StatusStreaming.Default.SendAllAsync(ApiData.From(new ApiSignal { Type = SignalType.Reseted, })); await AnonymousStreaming.Default.SendAllAsync(ApiData.From(new ApiSignal { Type = SignalType.Reseted, })); }