private EstateSettings CreateEstateInfo(Scene scene) { EstateSettings ES = new EstateSettings(); while (true) { IEstateConnector EstateConnector = DataManager.RequestPlugin <IEstateConnector>(); string name = MainConsole.Instance.CmdPrompt("Estate owner name", LastEstateOwner); UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, name); if (account == null) { string createNewUser = MainConsole.Instance.CmdPrompt("Could not find user " + name + ". Would you like to create this user?", "yes"); if (createNewUser == "yes") { // Create a new account string password = MainConsole.Instance.PasswdPrompt(name + "'s password"); string email = MainConsole.Instance.CmdPrompt(name + "'s email", ""); scene.UserAccountService.CreateUser(name, Util.Md5Hash(password), email); account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, name); if (account == null) { m_log.ErrorFormat("[EstateService]: Unable to store account. If this simulator is connected to a grid, you must create the estate owner account first."); continue; } } else { continue; } } LastEstateOwner = account.Name; string response = "no"; List <EstateSettings> ownerEstates = EstateConnector.GetEstates(account.PrincipalID); if (ownerEstates != null) { m_log.WarnFormat("Found user. {0} has {1} estates currently. {2}", account.Name, ownerEstates.Count, "These estates are the following:"); for (int i = 0; i < ownerEstates.Count; i++) { m_log.Warn(ownerEstates[i].EstateName); } response = MainConsole.Instance.CmdPrompt("Do you wish to join one of these existing estates? (Options are {yes, no})", LastEstateChoise, new List <string>() { "yes", "no" }); } else { m_log.WarnFormat("Found user. {0} has no estates currently. Creating a new estate.", account.Name); } LastEstateChoise = response; if (response == "no") { // Create a new estate ES.EstateName = MainConsole.Instance.CmdPrompt("New estate name", scene.RegionInfo.EstateSettings.EstateName); //Set to auto connect to this region next LastEstateName = ES.EstateName; LastEstateChoise = "yes"; string Password = Util.Md5Hash(Util.Md5Hash(MainConsole.Instance.CmdPrompt("New estate password (to keep others from joining your estate, blank to have no pass)", ES.EstatePass))); ES.EstatePass = Password; ES.EstateOwner = account.PrincipalID; ES = EstateConnector.CreateEstate(ES, scene.RegionInfo.RegionID); if (ES == null) { m_log.Warn("The connection to the server was broken, please try again soon."); continue; } else if (ES.EstateID == 0) { m_log.Warn("There was an error in creating this estate: " + ES.EstateName); //EstateName holds the error. See LocalEstateConnector for more info. continue; } //We set this back if there wasn't an error because the EstateService will NOT send it back IGenericsConnector g = DataManager.RequestPlugin <IGenericsConnector>(); EstatePassword s = new EstatePassword() { Password = Password }; if (g != null) //Save the pass to the database { g.AddGeneric(scene.RegionInfo.RegionID, "EstatePassword", ES.EstateID.ToString(), s.ToOSD()); } break; } else if (response == "yes") { if (ownerEstates.Count != 1) { response = MainConsole.Instance.CmdPrompt("Estate name to join", LastEstateName); if (response == "None") { continue; } LastEstateName = response; } else { LastEstateName = ownerEstates[0].EstateName; } List <int> estateIDs = EstateConnector.GetEstates(LastEstateName); if (estateIDs == null) { m_log.Warn("The connection to the server was broken, please try again soon."); continue; } if (estateIDs.Count < 1) { m_log.Warn("The name you have entered matches no known estate. Please try again"); continue; } int estateID = estateIDs[0]; string Password = Util.Md5Hash(Util.Md5Hash(MainConsole.Instance.CmdPrompt("Password for the estate", ""))); //We save the Password because we have to reset it after we tell the EstateService about it, as it clears it for security reasons if (EstateConnector.LinkRegion(scene.RegionInfo.RegionID, estateID, Password)) { if (EstateConnector.LoadEstateSettings(scene.RegionInfo.RegionID, out ES)) //We could do by EstateID now, but we need to completely make sure that it fully is set up { if (ES == null) { m_log.Warn("The connection to the server was broken, please try again soon."); continue; } //Reset the pass and save it to the database IGenericsConnector g = DataManager.RequestPlugin <IGenericsConnector>(); EstatePassword s = new EstatePassword() { Password = Password }; if (g != null) //Save the pass to the database { g.AddGeneric(scene.RegionInfo.RegionID, "EstatePassword", ES.EstateID.ToString(), s.ToOSD()); } } else { m_log.Warn("The connection to the server was broken, please try again soon."); continue; } m_log.Warn("Successfully joined the estate!"); break; } m_log.Warn("Joining the estate failed. Please try again."); continue; } } return(ES); }
/// <summary> /// This method will produce a random city with the central region of the city being /// specified as a parameter. More parameters need to be made available for this method /// to produce a better quality city, note for now the minimum area for a city is a /// 3x3 grid of regions. This code is based on the original C++ version called pixel city. /// </summary> /// <param name="seed_value">Random integer seed value.</param> /// <returns>true / false indicator of success or failure.</returns> private bool doGenerate(int seed_value) { int rx, ry; // Based on the initial seed value populate the regions that this shared module // is connected to, this means first get a list of the region, determine which // region is in the center of all the regions and set this as the hotzone, or // central part of the city (this is where the tallest/largest buildings will // be created) and will extend out to cover virtually all of the connected // regions if desired. No support for aging of the buildings or the city exists // yet it is a possible course for the future of this module. // TODO // // Validate the details in the configuration file against the settings in // the database, otherwise a new user/estate/parcel could be created which will // negate any of the security systems that Aurora has in place. // First quick check to see if the module is enabled or not. if (!m_fEnabled) { m_log.Info("[CITY BUILDER]: Disabled, aborting auto generation."); return (false); } m_log.Info("[CITY BUILDER]: Auto generating the city."); // Now we need to ask some basic values for the city generation, we already have // the base seed value as this is part of the 'city generate' command, now what // about a name, position, size, densities etc. Some of this can be generated // based on the seed value, but then, it would need to be confirmed by the user // or allow them to change it. TODO move all requested data into the configuration file. if (m_UserAccountService == null) { m_UserAccountService = simulationBase.ApplicationRegistry.RequestModuleInterface<IUserAccountService>(); } // Decide where the city is to be placed within the server instance. int r = CityModule.randomValue(10); string regionCount = MainConsole.Instance.CmdPrompt("Region Count ", r.ToString()); r = Convert.ToInt32(regionCount); m_log.InfoFormat("[CITY BUILDER]: City area {0} x {1} regions ", r, r); // Needs to be changed to use the 'defualt' properties and ask about the default // estate settings that are to be used, even if it is nothing more than just a // confirmation of the settings that are in the configuration file. cityName = MainConsole.Instance.CmdPrompt("City Name ", cityName); cityOwner = MainConsole.Instance.CmdPrompt("City Owner ", cityOwner); m_DefaultUserName = cityOwner; // Make sure that the user and estate information specified in the configuration file // have been loaded and the information has either been found or has been created. m_DefaultUserAccount = m_UserAccountService.GetUserAccount(UUID.Zero, cityOwner); if (m_DefaultUserAccount == null) { m_log.InfoFormat("[CITY BUILDER]: Creating default account {0}", m_DefaultUserName); m_UserAccountService.CreateUser(m_DefaultUserName, Util.Md5Hash(m_DefaultUserPword), m_DefaultUserEmail); m_DefaultUserAccount = m_UserAccountService.GetUserAccount(UUID.Zero, m_DefaultUserName); cityOwner = m_DefaultUserName; } else m_log.InfoFormat("[CITY BUILDER]: Account found for {0}", m_DefaultUserName); // Obtain the scene manager that the server instance is using. sceneManager = simulationBase.ApplicationRegistry.RequestModuleInterface<SceneManager>(); // Construct the data instance for a city map to hold the total regions in the simulation. cityMap = new CityMap(); citySeed = seed_value; cityMap.cityRegions = new Scene[r, r]; cityMap.cityPlots = new List<BuildingPlot>(); cityMap.cityBuildings = new List<CityBuilding>(); // Construct land and estate data and update to reflect the found user or the newly created one. cityLandData = new LandData(); RegionInfo regionInfo = new RegionInfo(); regionInfo.RegionID = UUID.Random(); // Determine if the default user account as specified in City Builder's configuration file // has any predefined estates, if so, just select the first one for now. Perhaps a search of // the estates to attempt to find a match to the details from the configuration file. EstateConnector = Aurora.DataManager.DataManager.RequestPlugin<IEstateConnector>(); // Valid estate connection established. if (EstateConnector != null) { // Valid estate connector, determine if the default user account has any estates. List<EstateSettings> estates = EstateConnector.GetEstates(m_DefaultUserAccount.PrincipalID); // No estates are found, so construct a new one based on the default estate settings // from the configuration file. if (estates == null) { // No estates present so construct one. m_DefaultEstate = new EstateSettings(); m_log.InfoFormat("[CITY BUILDER]: No estates found for user {0}, constructing default estate.", m_DefaultUserAccount.Name); m_DefaultEstate.EstateOwner = m_DefaultUserAccount.PrincipalID; m_DefaultEstate.EstateName = m_DefaultEstateName; m_DefaultEstate.EstatePass = Util.Md5Hash(Util.Md5Hash(m_DefaultEstatePassword)); m_DefaultEstate.EstateID = (uint)CityModule.randomValue(1000); regionInfo.EstateSettings = EstateConnector.CreateEstate(m_DefaultEstate, regionInfo.RegionID); } else { // Estates have been found, select the first estate in the list. No checking is done // against the configuration file settings. TODO validate the estate against the // configuration file. m_DefaultEstate = estates[0]; regionInfo.EstateSettings = m_DefaultEstate; m_log.InfoFormat("[CITY BUILDER]: {0} estates found for user {1}, selecting {2}", estates.Count, m_DefaultUserAccount.Name, m_DefaultEstate.EstateName); } } else { m_log.Info("[CITY BUILDER]: No connection with server."); return (false); } // Fill in land data for the estate/owner. cityLandData.OwnerID = m_DefaultUserAccount.PrincipalID; cityLandData.Name = m_DefaultEstateName; cityLandData.GlobalID = UUID.Random(); cityLandData.GroupID = UUID.Zero; int regionPort = startPort; // Construct the region. regionInfo.RegionSizeX = cityConfig.GetInt("DefaultRegionSize", 256); regionInfo.RegionSizeY = regionInfo.RegionSizeX; regionInfo.RegionType = "Mainland"; regionInfo.ObjectCapacity = 100000; regionInfo.Startup = StartupType.Normal; regionInfo.ScopeID = UUID.Zero; IParcelServiceConnector parcelService = simulationBase.ApplicationRegistry.RequestModuleInterface<IParcelServiceConnector>(); if (parcelService == null) { m_log.Info("[CITY BUILDER]: Unable to connect to servers parcel service."); } if (r == 1) { m_log.Info("[CITY BUILDER]: Single region city."); IPAddress address = IPAddress.Parse("0.0.0.0"); regionInfo.ExternalHostName = Aurora.Framework.Utilities.GetExternalIp(); regionInfo.FindExternalAutomatically = true; regionInfo.InternalEndPoint = new IPEndPoint(address, regionPort++); cityLandData.RegionID = regionInfo.RegionID; regionInfo.RegionName = "Region00"; regionInfo.RegionLocX = (int)m_DefaultStartLocation.X; regionInfo.RegionLocY = (int)m_DefaultStartLocation.Y; if (parcelService != null) parcelService.StoreLandObject(cityLandData); if (!createRegion(0, 0, regionInfo)) { m_log.Info("[CITY BUILDER]: Failed to construct region."); return (false); } } else if (r > 1) { m_log.Info("[CITY BUILDER]: Multi-region city."); m_log.Info("[CITY BUILDER]: Finding external IP, please wait ... "); regionInfo.ExternalHostName = Aurora.Framework.Utilities.GetExternalIp(); if (regionInfo.ExternalHostName.Length <= 0) { regionInfo.FindExternalAutomatically = false; } else { m_log.InfoFormat("[CITY BUILDER]: External IP address is {0}", regionInfo.ExternalHostName); regionInfo.FindExternalAutomatically = true; } // Construct the regions for the city. regionPort = startPort; INeighborService neighbours = simulationBase.ApplicationRegistry.RequestModuleInterface<INeighborService>(); if (neighbours == null) { m_log.Info("[CITY BUILDER]: No neighbours."); } else { m_log.Info("[CITY BUILDER]: Neighbours service found."); } IPAddress address = IPAddress.Parse("0.0.0.0"); for (rx = 0; rx < r; rx++) { for (ry = 0; ry < r; ry++) { regionInfo.InternalEndPoint = new IPEndPoint(address, regionPort++); cityLandData.RegionID = regionInfo.RegionID; regionInfo.RegionName = "Region" + rx + ry; regionInfo.RegionLocX = (int)(m_DefaultStartLocation.X + rx); regionInfo.RegionLocY = (int)(m_DefaultStartLocation.Y + ry); m_log.InfoFormat("[CITY BUILDER]: '{0}' @ {1},{2}, http://{3}/", regionInfo.RegionName, regionInfo.RegionLocX, regionInfo.RegionLocY, regionInfo.InternalEndPoint); if (parcelService != null) parcelService.StoreLandObject(cityLandData); if (!createRegion(rx, ry, regionInfo)) { m_log.InfoFormat("[CITY BUILDER]: Failed to construct region at {0},{1}", rx, ry); return (false); } if (neighbours != null) { m_log.Info("[CITY BUILDER]: Informing neighbours."); neighbours.InformOurRegionsOfNewNeighbor(regionInfo); } } } } // Either generate the terrain or loading from an existing file, DEM for example. m_log.Info("[CITY BUILDER]: [TERRAIN]"); // Construct the new terrain for each region and pass the height map to it. // For the entire area covered by all of the regions construct a new terrain heightfield for it. // Also construct several maps that can be blended together in order to provide a suitablly natural // looking terrain which is not too flat or doesn't entirely consist of mountains. float[,] terrainMap; float[,] hMap1; float[,] hMap2; float[,] hMap3; float[,] hMap4; float[] bFactors = new float[4]; int size = regionInfo.RegionSizeX; int y; int x; terrainMap = new float[ size * r, size * r ]; hMap1 = new float[ size * r, size * r ]; hMap2 = new float[ size * r, size * r ]; hMap3 = new float[ size * r, size * r ]; hMap4 = new float[ size * r, size * r ]; // Set blending factors. bFactors[0] = 0.75f; bFactors[1] = 0.55f; bFactors[2] = 0.35f; bFactors[3] = 0.05f; // Generate four layers for the initial height map and then blend them together. for (x = 0; x < size; x++) { for (y = 0; y < size; y++) { for (int i = 0; i < r; i++) { for (int j = 0; j < r; j++) { hMap1[i * x, i * y] = Perlin.noise2((float)x+i, (float)y+i); hMap2[i * x, i * y] = Perlin.noise2((float)x, (float)y+i); hMap3[i * x, i * y] = Perlin.noise2((float)x+i, (float)y); hMap4[i * x, i * y] = Perlin.noise2((float)x+j, (float)y+i); terrainMap[i*x, i*y] = (hMap1[i*x, i*y] * bFactors[0]) + (hMap2[i*x, i*y] * bFactors[1]) + (hMap3[i*x, i*y] * bFactors[2]) + (hMap4[i*x, i*y] * bFactors[3]); } } } } // DEBUG code that will save the resulting terrainMap as a jpeg image. m_log.Info("[CITY BUILDER]: Debug, save terrain map (full) as a jpeg image."); ManagedImage mImage = new ManagedImage(r * size, r * size, ManagedImage.ImageChannels.Bump); // Find a way of copying the terrainMap array into the newly created image, then save // the image to disk. m_log.Info("[CITY BUILDER]: Terrain built and blended, tiling and region application."); // Set the height map of each region based on the newly created terrainMap. ITerrain terrain = null; for (rx = 0; rx < r; rx++) { for (ry = 0; ry < r; ry++) { Scene region = cityMap.cityRegions[rx, ry]; ITerrainChannel tChannel = new TerrainChannel(true, region); region.TryRequestModuleInterface<ITerrain>(out terrain); m_log.InfoFormat("[CITY BUILDER]: Region [ {0}, {1} ]", rx, ry); float[,] tile = new float[ size, size ]; for (int i = 0; i < size; i++) { for (int j = 0; i < size; j++) { tile[i, j] = terrainMap[(rx * size) + i, (ry * size) + j]; } } if (terrain != null & tile!=null) terrain.SetHeights2D(tile); // dispose of the tile now thats its not needed as a new tile is allocated next loop run. tile = null; } } // Rivers and other waterways. Randomly select a number of rivers for the entire area // and place them. int rCount = CityModule.randomValue(size / r); m_log.InfoFormat("[CITY BUILDER]: River count for entire area {0}", rCount); // From the total number of regions pick a number of regions that will be 'centers' // for the entire city, record these in the centralRegions list. m_log.Info("[CITY BUILDER]: [CENTERS]"); // ( region count * region count ) / 3 int aNum = CityModule.randomValue((cityMap.cityRegions.GetUpperBound(0) * cityMap.cityRegions.GetUpperBound(1))/3); if (aNum == 0) { aNum = 1; } m_log.InfoFormat("[CITY BUILDER]: Total regions {0}, selecting {1} regions for centers.", (r*r), aNum ); int prevRegionX = 0; int prevRegionY = 0; while ( aNum > 0 ) { int currRegionX = randomValue( cityMap.cityRegions.GetUpperBound(0) ) / 2; int currRegionY = randomValue( cityMap.cityRegions.GetUpperBound(1) ) / 2; // If the location selected is the same as the previous location try again. if (currRegionX == prevRegionX && currRegionY == prevRegionY) { aNum--; continue; } m_log.InfoFormat("[CITY BUILDER]: Region {0}, located {1},{2}", aNum, prevRegionX, prevRegionY); try { Scene region = cityMap.centralRegions[(prevRegionX * cityMap.cityRegions.GetUpperBound(0)) + prevRegionY]; if (region!=null) { cityMap.centralRegions.Add(region); } } catch { } aNum--; prevRegionX = currRegionX; prevRegionY = currRegionY; } m_log.Info("[CITY BUILDER]: [DENSITY]"); float avgDensity = 0.0f; avgDensity += cityDensities[0]; avgDensity += cityDensities[1]; avgDensity += cityDensities[2]; avgDensity += cityDensities[3]; avgDensity /= 4; // Before ANYTHING else is created construct the transport systems, priority is given // to the road network before the rail network, perhaps a configuration option to allow // for the prioritisation value of the transport system is possible. m_log.Info("[CITY BUILDER]: [FREEWAYS]"); // Construct a road system (high speed ~50-70 mph) between and around the city center regions. m_log.Info("[CITY BUILDER]: [HIGHWAYS]"); m_log.Info("[CITY BUILDER]: [STREETS]"); m_log.Info("[CITY BUILDER]: [RAILWAYS]"); m_log.InfoFormat("[CITY BUILDER]: [RESIDENTIAL DENSITY] {0}%", cityDensities[0] * 100); m_log.InfoFormat("[CITY BUILDER]: [COMMERCIAL DENSITY] {0}%", cityDensities[1] * 100); m_log.InfoFormat("[CITY BUILDER]: [CORPORATE DENSITY] {0}%", cityDensities[2] * 100); m_log.InfoFormat("[CITY BUILDER]: [INDUSTRIAL DENISTY] {0}%", cityDensities[3] * 100); m_log.InfoFormat("[CITY BUILDER]: [AVERAGE DENSITY] {0}%", avgDensity); m_log.Info("[CITY BUILDER]: [BLOCKS]"); m_log.Info("[CITY BUILDER]: [ALLOTMENT PLOTS]"); m_log.Info("[CITY BUILDER]: [BUILDINGS]"); return (true); }