• Moose
  • Announcements

    • Dirktator

      Please help us for June & July   06/20/2017

      This month we're hoping for a little bit of a boost this month or next, in addition to covering the regular bills, we'd love to be able to do some hardware upgrades. STEX Collector's Set gifts can now be sent to you via digital download as well as regular mail if you wish! Every donation dollar goes toward keeping Simtropolis online and humming along. Your contribution is so meaningful, every dollar counts! Hardware Upgrades We've received a recommendation to consider some hardware upgrades to our ageing server. As our website community software improves with more and more features, and as we bolt on additional features such as chat, the increased load to handle all these new toys is taking the server a bit to task. You may have noticed that we'd been forced to temporarily disable the chat as we worked out allocating resources for more optimal performance. Following this, we've applied a number of 'soft' changes such as caching options and experimented with server configurations (nginx as proxy, for example), so the hardware aspect is also an area we'd like to focus on. The last time we upgraded hardware was back in 2012, prior to the release of SC13. Your contribution means a lot! Your donation will go toward helping us to 1.) migrate to a newer server or 2.) at least get some ram/cpu/storage updates and any other infrastructure hardware or services. Donate and Get a Gift or Donate Any Amount Thanks so much! - Dirktator & The Admins
CorinaMarie

C.O.R.I.M.A.P.S. - A Tutorial for SimCity 4

108 posts in this topic

19 minutes ago, APSMS said:

Other test would be trying to load the images directly, either by right-clicking "view image" or seeing if you can access normal photobucket.com period, away from ST.

That's your best workaround. Probably just the embedded re-direct that's a problem.

huzman likes this

Share this post


Link to post
Share on other sites
9 hours ago, CorinaMarie said:

(I don't even know what that is.)

I meant Pocketbucket.com.

8 hours ago, APSMS said:

Sounds like an ISP issue to me; etc...

Could you explain ISP to me ?

On the other hand, I can see the images of @Haljackey, in the "show-us-what-you-are-working-on" thread.

Share this post


Link to post
Share on other sites
1 hour ago, huzman said:

Could you explain ISP to me ?

ISP = Internet Service Provider.

@APSMS is suggesting something there, such as their settings, might be what is blocking you from seeing the pics I've hosted on PB (PhotoBucket).

 

1 hour ago, huzman said:

On the other hand, I can see the images of @Haljackey, in the "show-us-what-you-are-working-on" thread.

He uses Imgur and not PB, so that tells us you can see pics hosted at that site. Did you see the topographical maps pics I posted a few posts back? If not, that's more indication that it's related to PB. Is there a chance that you flagged the PB site as an always block? Like in Ad Blocker Plus if you are using Firefox. Or some other version of site blocking?

huzman and APSMS like this

Share this post


Link to post
Share on other sites

Thanks for your quick answers. I solved the problem by reinstalling FF. "Big Problem, Drastic Solutions". I even caught some images that I missed. Yeah !!!

Really appreciate the dedication you give. So here is the continuation of my heights research : here I eliminated the 83 level. As you can see, the 84 level goes right into the water but harbors are hard to place. I used the leveler "gentle slopes to beaches"  but still no luck.

 

Nova Região.zip


  Edited by huzman
CorinaMarie likes this

Share this post


Link to post
Share on other sites

Glad the FF reinstall worked, but it would have been helpful to you if you could have put your finger on the blockage. Now you may be exposed to other problems.

For the curious, the blockage could have been an addon like AdBlock, but it could also have been a FF bandwidth control setting about loading images. The most tricky blockage I have diagnosed was when a security tool added a couple hundred entries to my hosts file, redirecting a bunch of "known scam sites" to a null IP address.

All those domains were then unreachable, and the cause of the blockage was like 3 layers deep down in the Windoze system folders. After having two years to forget about those host file entries, It turned out that one of the black-listed domains also hosted some legit traffic that I wanted to see.

CorinaMarie, huzman and APSMS like this

Share this post


Link to post
Share on other sites
13 hours ago, huzman said:

So here is the continuation of my heights research : here I eliminated the 83 level. As you can see, the 84 level goes right into the water but harbors are hard to place.

I downloaded your new region and I've loaded your 83-84-3.bmp grayscale. I then use the color picker eyedropper and here's what I see in both of my imaging programs:

Gray%20Color%20Pick_zps1j0iaejh.jpg

I'm confuzzled as to why none of the numbers seem right. I'm expecting to see 84 in there somewhere since I sampled the lightest gray in the center of your image. Yet, obviously, they render to the right height in game.

o.O

mrsmartman and huzman like this

Share this post


Link to post
Share on other sites
10 hours ago, jeffryfisher said:

For the curious, the blockage could have been an addon like AdBlock,

That's what I suspected. But I think PhotoBucket  is partially involved. When I first came here, PB was snowing me with pub/spam.

 

8 hours ago, CorinaMarie said:

I'm confuzzled as to why...

In actual painting, there are several ways to obtain a specific color. Of course Digital Coloring is completely different, but perhaps the same principle holds.

Share this post


Link to post
Share on other sites
2 hours ago, RobertLM78 said:

Although, I make use of Ordio's SCRACC utility for doing the config files.

Looks quite interesting. I edited a linky to Ordio's program into my initial post to draw attention to it as a fourth alternative option. I haven't installed it myself, but am I correct to presume one could load their own grayscale in SCRACC and then make the config.bmp?

huzman and RobertLM78 like this

Share this post


Link to post
Share on other sites
On 2/23/2017 at 10:42 PM, jeffryfisher said:

Now you may be exposed to other problems.

Right on, brother ! It's a real can of worms. But since I can see those Pocketbucket pix, I don't mind too much correcting those glitches.

CorinaMarie : what are you using to open the "simcity_1.dat" in text form ? And what do use for the topographical maps ?

Share this post


Link to post
Share on other sites
39 minutes ago, huzman said:

what are you using to open the "simcity_1.dat" in text form ?

I use iLive's Reader. There are two main versions:

The 0.93 version is more stable. The 1.54 version is needed for the more complicated exemplars. Some variables simply will not show in the 0.93 version.

 

39 minutes ago, huzman said:

And what do use for the topographical maps ?

I take a screen shot of the All Off data view, load it into GIMP, zoom in a bunch, and then crop out the mini map. I do that for each city tile and then paste them into position in a larger, blank image. (So for my 4 x 4 large tile region I make the new file be 1024 x 1024 so all 16 images will fit.) It's a tedious and time consuming process, but I love the end result so it's worth it to me.

Topo%20Map%20Crop_zpstli9u6cz.jpg

 

And for reference, @huzman is referring to this pic back on page 2:

Spoiler

Topo%20Map_zpseb5alxeh.jpg

And I then use the line tool to create pseudo grid lines cause the seams between the stitched images are not perfect.

Share this post


Link to post
Share on other sites
52 minutes ago, CorinaMarie said:

I take a screen shot of the All Off data view,

I take it to be from inside the iLive's Reader. While writing this, I downloaded all the iLive's Reader files.

You know ? I spend more time downloading and installing things than actually working on them. It's getting a little boring.

Share this post


Link to post
Share on other sites
2 minutes ago, huzman said:

I take it to be from inside the iLive's Reader.

To make my topo map I take all the initial screen shots in the game itself (with the data view open).

 

3 minutes ago, huzman said:

You know ? I spend more time downloading and installing things than actually working on them. It's getting a little boring.

It's good to gather all the tools you might want to use. Just toss them in your toolbox for later.

huzman likes this

Share this post


Link to post
Share on other sites
9 hours ago, CorinaMarie said:

...am I correct to presume one could load their own grayscale in SCRACC and then make the config.bmp?

You betcha!  :D

CorinaMarie likes this

Share this post


Link to post
Share on other sites
On ‎2017‎-‎02‎-‎25 at 3:52 AM, CorinaMarie said:

fourth alternative option

I think I just discovered a 5th alternative option.  I was getting back to making grayscales and also using SC4 Mapper tonight.  I never realized this before, but I can terra-form in-game, then load the region in SC4 Mapper and export both an .SC4M file and an RGB bitmap.   The bitmap can then be converted to a grayscale --indexed 256 8-bit bmp.   I'm going to have a lot of fun with this discovery.  I'll be editing my map files and including links back to this thread as it is now the active repository of map-making knowledge for SC4.

huzman, CorinaMarie and RobertLM78 like this

Share this post


Link to post
Share on other sites
On 2/25/2017 at 4:49 AM, RobertLM78 said:

Ordio's SCRACC utility

Phooey. This seems to have suddenly gone missing. Says the Members Webspace has been retired. Thankfully I got a copy of it when I did and I archived the help page too.

RobertLM78 and huzman like this

Share this post


Link to post
Share on other sites
6 minutes ago, CorinaMarie said:

Phooey. This seems to have suddenly gone missing. Says the Members Webspace has been retired. Thankfully I got a copy of it when I did and I archived the help page too.

Dang... that's not the first time that's happened recently.  About a month or two ago, the best mirror of SOMY's (http://members3.jcom.home.ne.jp/somy000/) stuff is no longer up either.  There is the other site, http://members3.jcom.home.ne.jp/somy000/, as of yet, I haven't figured out how he's separated the large zip files (apparently I can't 'cat' them back together - and he probably used something on Windoze).

Does anyone know Ordio?  It would be nice to have the utility uploaded somewhere else.

huzman likes this

Share this post


Link to post
Share on other sites

To go back to gray mapping and levels tests AND since it has been a while, here is recapitulation of things :

Gray Mapping : for the time been, this is the way to go for me. But in most -95%- of the maps, placing harbors are impossible to lay. (I found gray maps of harbor cities here and there, and in many of the harbor problem was incredible, if not impossible.) Even on a single level of a 84 level in a map, the difficulty persists. The only solution I found is using the "Smoothing" tool in God's Mode on the beaches, after generating the map. In maps with different levels (84-85-86, etc. or 84-94-104 and so on) the smoothing tool is also good to create nice smooth transitions between levels, in the hills even steep ones (84-104-124 and such). The hick is that one has to smooth the whole region, daunting...

I kept a few screen shots of cities that are not saved in the game. They show the three harbors placement, roads going up hill showing default low level residences (I mean placing one residence, holding it down for a second or two, and a largish grid shows up. Two reasons : How close to the water line houses will be built and using the land 'as is'. The Pix show one half of the landscape smoothed out, the other raw terrain. (you get some really weird results like that.) Those pictures are not ready to upload as of this writing, but if there's enough interest in them...

So to conclude : I'm giving up on the whole thing. It was taking too much time from actually playing. Let's not even talk about transportation frustration with the NAM options or even with the vanilla flavor of roads, avenues, highways, trains, monorails, et all. But that's another topic.

APSMS, CorinaMarie and RobertLM78 like this

Share this post


Link to post
Share on other sites

@huzman You have certainly given this a lot of time and effort. If it's not working out how you like then whatever alternative you find that is better is the way to go. Btw, have you tried any of the three programs I linked to near the beginning of my first post? I know lots of peeps like them. I pretty much came up with this idea here for two reasons. First, I mostly wanted to understand how the original game worked with grayscale map import and rendering. And second, there were some peeps saying they could not run the other programs so they didn't have an alternative.

Feel free to post your pics here and discuss the techy parts of what is good or bad. It's all about learning and sharing that knowledge with others. *;)

RandyE, APSMS, huzman and 1 other like this

Share this post


Link to post
Share on other sites

I've found that for regional editing tools, SC4Terraformer covers a wealth of sins. My Republic City map (from Legend of Korra) was initially created in grayscale by painting over a map of the city that I found online. I then imported it into Terraformer and further smoothed out all the rough spots.

I think it needs another go around to be proper quality (sampling from some other real-world maps would go a very long ways to perfection, but I'm not setup for it at the moment) but in getting the map into the game I don't think I did so bad. It's worth noting that the map was considerably worse before Terraformer and would look nowhere near as smooth if I'd tried to only use the tools available in the game.

I might also mention that whole thing took me about two months, if I remember correctly.

huzman and CorinaMarie like this

Share this post


Link to post
Share on other sites
10 hours ago, CorinaMarie said:

Btw, have you tried any of the three programs I linked to near the beginning of my first post?

Yes mademoiselle, I have all of them, but I have used them very little as I'm a little confused on how to use them. But I shall persevere !

9 hours ago, APSMS said:

SC4Terraformer covers a wealth of sins

Yes, and it is also truth about the others. Too bad I didn't get to download the

On 3/19/2017 at 7:52 PM, CorinaMarie said:

Ordio's SCRACC utility.

 

CorinaMarie likes this

Share this post


Link to post
Share on other sites
2 hours ago, huzman said:

Too bad I didn't get to download the Ordio's SCRACC utility.

I believe it now falls in the Abandonware category. I'll attach it here with the caveat that if Ordio does not want it to be available it will be removed. The file is a Windoze .msi installer file. I've also included an archive of the help page. It's in the Mozilla Archive Format so you will need Firefox and that addon to view it. (It's not required to use SCRACC.)

SCRACC.zip

RobertLM78 and huzman like this

Share this post


Link to post
Share on other sites
3 hours ago, CorinaMarie said:

Right up my alley. Muchas gracias señorita.

As for some results of my feeble tries, here they are in a bundled zip. Some explanations : some file names may be misleading, as some images show BOTH the  'smoothed' out in one side (mostly North) and the other (south) is left as is. The placement of the three harbors is rather obvious. The roads are meant so show inclination and easy transition from level to level. I extended the roads down the beaches to see how far they could go. Then the long roads with R grids. It is the same idea : show smoothness in one side and the rough rendering in the other.

(I just noticed that I'm repeating myself "a wee bit" -as used by a estimated colleague-) but is all in the clarification of things. One last thing: The topography for land starts at level 84. Water is deep at level 40. No feathering, no antialiasing, just hard edge levels. And that was a pain the neck. That and @CorinaMarie's 'B&B' (Burn and Blur) techniques is my next step.

Hope to having contributing something useful. I reached max uploading size -4MB- so the others will be in a next post

Fanta-Both1.png

Fanta-NO-terra3.png

Fanta-terra.png

RandyE and mrsmartman like this

Share this post


Link to post
Share on other sites

Cori,

(1)  What is the largest map/region which can be made for SC4 in terms of bit map dimensions?

(2)  Do you know of some Web site similar to Google Maps, but that would allow grayscale topological maps?

This is what I have found.  Seems a bit of installing, but once you got it done, you can get a grayscale for any location earth for an SC4 region.

https://www.matterhackers.com/news/how-to-3d-print-a-map-of-anywhere-in-the-world

Too bad I wish I could just click on something in Google and print topological in grayscale.

Share this post


Link to post
Share on other sites
8 hours ago, huzman said:

As for some results of my feeble tries, here they are in a bundled zip.

Those pics look fine to me. I've personally never been concerned if I can immediately place a seaport or ferry on the existing rendered terrain. I use the mayor mode tools and do a wee bit of terraforming to tweak the area to make it ready to plop those. (Btw, I don't see a file attached to your post. I'm guessing you mean you reached the 4mb limit because of the attached pictures.)

For the streets and roads you might like the effect of using a Slope Mod.

 

2 hours ago, MarkShot said:

(1)  What is the largest map/region which can be made for SC4 in terms of bit map dimensions?

I don't know if there is an actual limit for rendering from a bit map. The largest I've created was 10 x 10 (100 total) large tiles.  The grayscale was 2561 x 2561 pixels. I've seen the generic version of the question how large can a region be and the answer is however big your comp can handle.

 

2 hours ago, MarkShot said:

(2)  Do you know of some Web site similar to Google Maps, but that would allow grayscale topological maps?

Offhand I don't know of a site. Back when I was learning about maps for SC4 I did read stuff about using Google Maps and also downloading Digital Elevation Models (DEMs) from the Geological Survey site.  The thing with the DEMs is one has to convert them to a grayscale image and the data is byte reversed or something. (Been too long since I read about it to have the wording exactly right.) Anyhow, the process for the conversion from a DEM was definitely within my programming ability. I just never got around to doing it since I was happy enough with my Cloud Method. And too, I then got side tracked creating my Shoppes catalogues. And after that I got side tracked farming an entire region with those farms style like central Indiana. (You may have seen those pics in the Show Us thread starting on page 17.)

So, I really don't have any good answer for this second question. It is still of interest to me, but more like way later in the future.

huzman likes this

Share this post


Link to post
Share on other sites
3 hours ago, MarkShot said:

(1)  What is the largest map/region which can be made for SC4 in terms of bit map dimensions?

Theoretically, you can go until your RAM runs out (that is, the program is no longer able to address additional memory).

I suspect the Los Angeles Metro Area is pushing the upper limit of practicality, even if you can go bigger. The map measures 37 by 24 (large city tiles), or 147.456km by 98.304km for a total area of ~14 500 sq.km (~5600 sq.mi), which IIRC is bigger than the actual LA county, although the map itself I notice contains bits of Orange, Riverside, San Bernadino, and Ventura Counties. LA county extends much further northward.

Too big to be practically usable for sure. A lifetime of SC4 might not fill that map!

EDIT: I found a bigger map, with the caveat that there's less land:

122.88km by 139.264 km!

mrsmartman, huzman and CorinaMarie like this

Share this post


Link to post
Share on other sites

Hi Cori, I've been using Windows 10 and Microsoft Office picture manager, I've got to the point of placing the greyscale image in the region but similarly to huzman, nothing happens. 

I:

Created a new confi.bmp to a modest 12x18 pixels, saved over existing.

Got a nice picture of some clouds of wikimedia, cropped the useless parts and resized the image using the forumla.

Put saturation to -100 to create a greyscale image.

Exported as bmp, saved it as "Grey2"

Opened up SC4, pressed CTRL+ALT+SHIFT+R, selected my cloud image and nothing happens.

Any advice on what's going on? Is it Windows 10 or the puny Microsoft Picture Manager?

 

Thanks

RandyE likes this

Share this post


Link to post
Share on other sites

The function to render greyscale maps from region view is exceedingly limited in terms of what it will accept. You'd be much better off using an application such as SC4 Mapper or Landscape designer to create the actual region heightmap. Armed with an export from these, you can simply select your new region as you would any other.

Share this post


Link to post
Share on other sites
1 hour ago, rsc204 said:

The function to render greyscale maps from region view is exceedingly limited in terms of what it will accept. You'd be much better off using an application such as SC4 Mapper or Landscape designer to create the actual region heightmap. Armed with an export from these, you can simply select your new region as you would any other.

From my experience it seems that everything needs to be absolutely correct, especially with the pixel size of the greyscale:

64 x LENGTH IN km + 1 = # PIXELS FOR GREYSCALE MAP

So, for 5x5 large map file:

64 x (5x4) + 1 = 1281pixels, or 1281x1281 pixels, since it's a 5x4 large map. 

rsc204, CorinaMarie and RandyE like this

Share this post


Link to post
Share on other sites
5 hours ago, armpit43 said:

Put saturation to -100 to create a greyscale image.

I believe this might be the culprit. Although that does change the coloring to a grayscale appearance, it is still likely in RGB file format. Look for an option to actually change the mode to grayscale.

APSMS and RandyE like this

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an Account  

Sign up to join our friendly community. It's easy!  :thumb:


Register a New Account

Sign In  

Already have an account? Sign in here.


Sign In Now


  •  
  • Similar Content

    • By DJDL
      Hello Simtropolis Community!
      I am looking to buy a new Windows laptop and I would appreciate your input.  Along with the usual Office functions, my goal will be gaming (SC4, possibly Civ 3 and eventually Cities Skylines) and graphics/dtp (Adobe).
      These are the machines (all Dell) that I am considering. and I'm hoping to purchase a new machine this weekend, since there's a sale going on.
      Inspiron 5000 Gaming with Win10 Pro
      7th Generation Intel® Core™ i7-7700HQ Quad Core (6MB Cache, up to 3.8 GHz) 8GB, 2400MHz, DDR4; up to 32GB NVIDIA® GeForce® GTX 1050 with 4GB GDDR5 128GB Solid State Drive (Boot) + 1TB 5400 rpm Hard Drive (Storage) 15.6-inch FHD (1920 x 1080) Anti-Glare LED-Backlit Display 74WHr, 6-Cell Battery (Integrated) "optimal cooling" Ports 1 HDMITM 1.4a
      3 USB 3.0 including 1 with PowerShare
      1 2-in-1 SD (UHS50) / MMC
      1 RJ-45
      1 Kensington Lock
      1 Headphone/Mic Inspiron 15 7000 Gaming with Win 10 Pro
      7th Generation Intel® Core™ i5-7300HQ Quad Core (6MB Cache, up to 3.5 GHz) or 17-7700HQ Quad, 6MB up to 3.8GHz)  8GB, 2400MHz, DDR4; up to 32GB or 16GB, 2400MHz, DDR4; up to 32GB 256GB Solid State Drive or 128GB Solid State Drive (Boot) + 1TB 5400RPM Hard Drive (Storage) 15.6-inch FHD (1920 x 1080) IPS Anti-Glare LED-Backlit Display NVIDIA® GeForce® GTX 1050Ti with 4GB GDDR5 74 Whr, 6-Cell Battery (Integrated) Ports and Slots: Combo Jack (Headset/Mic, USB 3.0 port, USB 3.0 Powershare port, HDMI, Gigabit Ethernet, Noble Lock Security Slot, Power, 8.USB 3.0 port, Media Card Reader front-firing speakers, a subwoofer and Waves MaxxAudio® Pro. maximum cooling feature Inspiron 17 7000 2in1 with Win 10 Pro--I'm considering two machines which share the following specs
      7th Generation Intel® Core™ i7-7500U Processor (4M Cache, up to 3.5 GHz) 16GB, DDR4, 2400MHz NVIDIA® GeForce® GTX 940MX 2GB GDDR5 17.3-inch FHD (1920 x 1080) Truelife LED-Backlit Touch Display with Wide Viewing Angles 56 WHr, 4-Cell Battery (integrated) The differences are the HD and port/slots: 1TB 5400 rpm Hard Drive; Ports:   SD, SDHC, SDXC Card Reader (specified), USB 2.0, Noble Lock Slot,  DC Power In, USB Type C, HDMITM 1.4a (specified), USB 3.0 with PowerShare, Audio Jack  1TB 5400 rpm Hard Drive + 128GB Solid State Drive (for about $40 more); Ports:  SD Card Reader, USB 2.0, Noble Lock Slot, DC Power In, USB Type C, HDMI, USB 3.0 with PowerShare,. Audio Jack XPS 15 with Win 10 Pro (priciest)
      7th Generation Intel® Core™ i7-7700HQ Quad Core Processor (6M cache, up to 3.8 GHz) 16GB DDR4-2400MHz; up to 32GB (additional memory sold separately) 512GB PCle Solid State Drive NVIDIA® GeForce® GTX 1050 with 4GB GDDR5 15.6" FHD (1920 x 1080) InfinityEdge, Non-touch Killer 1535 802.11ac 2x2 WiFi and Bluetooth 4.1 Battery: 97WHr Ports: SD card slot, USB 3.0 with PowerShare, Battery gauge button and indicator, Kensington lock slot, AC power, HDMI, Thunderbolt™ 3 (2 lanes of PCI Express Gen 3) supporting: Power in/charging, PowerShare, Thunderbolt 3 (40Gbps bi-directional), USB 3.1 Gen 2 (10Gbps), Native DisplayPort 1.2 video output, VGA, HDMI, Ethernet and USB-A via Dell Adapter (sold separately) | 8. Headset jack  (I'm not planning on buying the Dell Adapter) I like aspects of each machine, bigger screen for one, SSD, cooling feature, (SC4 and flash games are dangerously hot on my present machine), and graphics card.  I just wish they all came on one machine.  I would consider upgrading my existing machine but the motherboard on my TOSH Satellite is pretty archaic by today's standards so much so that a previous Win 10 update knocked out the functionality of my native keyboard.  I got a new one and it has the same issue, so I'm using a wireless one after breaking a USB keyboard.
      Thank you all for your help!
      Diana
    • By Silur
      I'm curious to know Your opinion about the website Simtropolis. Today I started editing one site in my country. And I realized that this is far from the quality that I see on Simtropolis. How do You compare the quality of most of the other sites? Are there any sites built even more conveniently?  Are there any ideals in this world? Thank you.
    • By boformer
      In this tutorial, we will replicate the functionality of the "Make Historical" checkbox in SimCity 4 (stop building from leveling up). The mod will utilize the same interfaces as the Control Building Level Up mod. You will learn how to inspect and modify user interfaces with ModTools, how the info panels of the game work, how to add a checkbox to the UI, how to control building level up with the official API, how to get notified when a building is added/removed and how to serialize custom data in the savegame. Once again, we will use the loading and threading hooks provided by the API.

       
      Step 1: Project Setup
      Create a new project named "MakeHistorical" in VS2017, following Method 2 in Tutorial 0 (working with a text editor is still possible in this tutorial, but not recommended)
      Your IUserMod implementation should look like this:
      using ICities; namespace MakeHistorical { public class MakeHistoricalMod : IUserMod { public string Name => "Make Historical"; public string Description => "Prevents the level up of buildings"; } }  
      Step 2: Data Storage with Serialization Hook
      Data Structure
      We will store the ids (ushort) of the historical building instances in the savegame. Like in Tutorial 2 Step 4, we will create a data class that holds our data:
      using System.Collections.Generic; namespace MakeHistorical { public class MakeHistoricalData { public List<ushort> HistoricalBuildingIds { get; set; } = new List<ushort>(); } } The game requires additional savegame data to be in byte[] (byte array) format (basically zeros and ones, very low level). Luckily, Colossal Order provides a few useful tools to convert data classes to byte arrays (package ColossalFramework.IO). To use these tools, our data class must implement the IDataContainer interface.
      Extend the class like this:
      using System.Collections.Generic; using System.Linq; using ColossalFramework.IO; namespace MakeHistorical { public class MakeHistoricalData : IDataContainer { // The key for our data in the savegame public const string DataId = "MakeHistorical"; // Version of data save format // This is important when you add new fields to MakeHistoricalData public const int DataVersion = 0; public List<ushort> HistoricalBuildingIds { get; set; } = new List<ushort>(); // This serializes the object (to bytes) public void Serialize(DataSerializer s) { // convert ushort list to int array int[] ids = HistoricalBuildingIds.Select(id => (int)id).ToArray(); s.WriteInt32Array(ids); } // This reads the object (from bytes) public void Deserialize(DataSerializer s) { int[] ids = s.ReadInt32Array(); // convert int array to ushort list HistoricalBuildingIds = ids.Select(id => (ushort)id).ToList(); } // Validates that all building ids are active public void AfterDeserialize(DataSerializer s) { if (!BuildingManager.exists) return; List<ushort> validatedBuildingIds = new List<ushort>(); Building[] buildingInstances = BuildingManager.instance.m_buildings.m_buffer; // itertate through all building ids, filter active ids foreach (ushort buildingId in HistoricalBuildingIds) { if (buildingInstances[buildingId].m_flags != Building.Flags.None) { validatedBuildingIds.Add(buildingId); } } HistoricalBuildingIds = validatedBuildingIds; } } } What happened?
      We added the constants DataId and DataVersion. We will use these in the next step We implemented the Serialize method: In this method, we convert our list of ushort numbers to an integer array (the serializer does not support ushort) and pass it to a DataSerializer, which converts our array to bytes. We implemented the Deserialize method, which does the opposite of Serialize We implemented AfterDeserialize, which validates that all deserialized building ids belong to buildings (important when the mod was disabled for some time, to keep the data clean) Serialization System
      Colossal Order provides a serialization hook for mods (ISerializableDataExtension/SerializableDataExtensionBase). This hook is invoked when the savegame data is loaded, and when the user presses the save button. The game also provides a storage interface (ISerializableData) that allows us to write byte arrays to savegame and read byte arrays from savegame.
      Combined with the data class and the byte array conversion tools provided by Colossal Order, we will use this hook to save our data. Add a new MakeHistoricalDataManager class:
      using ColossalFramework.IO; using ICities; using System.IO; using UnityEngine; namespace MakeHistorical { public class MakeHistoricalDataManager : SerializableDataExtensionBase { // The data object of our mod private MakeHistoricalData _data; public override void OnLoadData() { // Get bytes from savegame byte[] bytes = serializableDataManager.LoadData(MakeHistoricalData.DataId); if (bytes != null) { // Convert the bytes to MakeHistoricalData object using (var stream = new MemoryStream(bytes)) { _data = DataSerializer.Deserialize<MakeHistoricalData>(stream, DataSerializer.Mode.Memory); } Debug.LogFormat("Data loaded (Size in bytes: {0})", bytes.Length); } else { _data = new MakeHistoricalData(); Debug.Log("Data created"); } } public override void OnSaveData() { byte[] bytes; // Convert the MakeHistoricalData object to bytes using (var stream = new MemoryStream()) { DataSerializer.Serialize(stream, DataSerializer.Mode.Memory, MakeHistoricalData.DataVersion, _data); bytes = stream.ToArray(); } // Save bytes in savegame serializableDataManager.SaveData(MakeHistoricalData.DataId, bytes); Debug.LogFormat("Data saved (Size in bytes: {0})", bytes.Length); } } } What happens here?
      The _data property stores our mod data The OnLoadData method attempts to read the saved byte array from the savegame. If the array was found, it converts the bytes to a MakeHistoricalData object (our data structure). If no array was found, it creates a new MakeHistoricalData object (new city or mod enabled for the first time). The OnSaveData method converts the MakeHistoricalData object to bytes, then saves the bytes in the savegame. Tip: To understand how data versioning works, look at this example data manager.
      Singleton
      To make the data readable from other classes, we will make MakeHistoricalDataManager implement a simple singleton pattern. We willl also add a few methods to lookup, add and remove building ids:
      // Singleton getter public static MakeHistoricalDataManager Instance { get; private set; } public bool IsHistorical(ushort buildingId) { return _data.HistoricalBuildingIds.Contains(buildingId); } public void AddBuildingId(ushort buildingId) { if (_data.HistoricalBuildingIds.Contains(buildingId)) return; _data.HistoricalBuildingIds.Add(buildingId); Debug.Log($"Historical Building {buildingId} added"); } public void RemoveBuildingId(ushort buildingId) { if (!_data.HistoricalBuildingIds.Contains(buildingId)) return; _data.HistoricalBuildingIds.Remove(buildingId); Debug.Log($"Historical Building {buildingId} removed"); } public override void OnCreated(ISerializableData serializedData) { base.OnCreated(serializedData); Instance = this; // initialize singleton } public override void OnReleased() { Instance = null; // reset singleton } Now we can use a simple statement to check if a building is historical:
      bool h = MakeHistoricalDataManager.Instance.IsHistorical(1234); Final code of the MakeHistoricalDataManager class.
       
      Step 3: Removing destroyed buildings from the list
      We have to remove buildings from the list when they are buldozed. Luckily CO added a hook just for that (not documented in the wiki):
      using ICities; using UnityEngine; namespace MakeHistorical { public class MakeHistoricalBuildingMonitor : BuildingExtensionBase { public override void OnBuildingReleased(ushort id) { if (MakeHistoricalDataManager.Instance.IsHistorical(id)) { // Remove demolished/destroyed buildings from the list of historical buildings MakeHistoricalDataManager.Instance.RemoveBuildingId(id); } } } } Tip: With the IBuildingExtension/BuildingExtensionBase hook, you can also manipulate which buildings are spawned, and there are hooks for building creation and relocation.
       
      Step 4: Inspecting And Manipulating User Interfaces with ModTools and ILSpy
      Like in SimCity 4, we will add a "Make Historical" checkbox to the building info window:

      To do that, we have to find out how to access the info window programmatically.
      ModTools supports us with its "debug view". You can toggle it with CTRL + R. Then move your mouse over the info panel (so that the tint of the panel changes to green) and press CTRL + F:

      The UI window component is now displayed in the ModTools scene explorer. The class name of the element is ZonedBuildingWorldInfoPanel.
      In the scene explorer, we can change properties like the colour, size and position of the window. We can also look at the child UI elements (buttons, text labels). The position of the child elements is determined by the relativeLayout property.
      Noted values:
      Height: 321 Left Padding: 14 (based on the child element positions) Bottom Padding: 27 (based on the child element positions) Now that we know the class name, we can locate the class in ILSpy to find out how to access it programmatically:

      ZonedBuildingWorldInfoPanel is a subclass of WorldInfoPanel, which contains a static Show<>() method:
      // WorldInfoPanel (taken from ILSpy) public static void Show<TPanel>(Vector3 worldMousePosition, InstanceID instanceID) where TPanel : WorldInfoPanel { TPanel tPanel = UIView.library.Show<TPanel>(typeof(TPanel).Name, false); tPanel.SetTarget(worldMousePosition, instanceID); tPanel.component.opacity = 1f; } After further investigation (use ILSpy's "Analyze" feature), you will find a Get<>() method in UIView.library which returns the ZonedBuildingWorldInfoPanel instance:
      var panel = UIView.library.Get<ZonedBuildingWorldInfoPanel>(typeof(ZonedBuildingWorldInfoPanel).Name); Note: There is only one panel instance, which is just filled with the data of the currently selected building. The panel even exists when no building is selected, it's just hidden.
       
      Step 5: Adding a Checkbox to the Info Panel
      Finding the right property values for user interfaces is a finicky task, especially when you have to restart the game after every little change. Using the ModTools console, we can add and modify our checkbox while the game is running. Run this script in the ModTools console (F7):
      var panel = UIView.library.Get<ZonedBuildingWorldInfoPanel>(typeof(ZonedBuildingWorldInfoPanel).Name); var checkBox = panel.component.AddUIComponent<UICheckBox>(); checkBox.width = panel.component.width; checkBox.height = 20f; checkBox.clipChildren = true; UISprite sprite = checkBox.AddUIComponent<UISprite>(); sprite.spriteName = "ToggleBase"; sprite.size = new Vector2(16f, 16f); sprite.relativePosition = Vector3.zero; checkBox.checkedBoxObject = sprite.AddUIComponent<UISprite>(); ((UISprite)checkBox.checkedBoxObject).spriteName = "ToggleBaseFocused"; checkBox.checkedBoxObject.size = new Vector2(16f, 16f); checkBox.checkedBoxObject.relativePosition = Vector3.zero; checkBox.label = checkBox.AddUIComponent<UILabel>(); checkBox.label.text = " "; checkBox.label.textScale = 0.9f; checkBox.label.relativePosition = new Vector3(22f, 2f); checkBox.name = "MakeHistorical"; checkBox.text = "Make Historical"; This will add everything that is required for a checkbox, giving it the name "MakeHistorical". It is still in the wrong position:

      Tip: SamsamTS created a very useful utility class that allows you to create various UI elements. The code above was copied from that class.
       
      With ModTools, we can experiment with the position without restarting the game. Execute this code in the ModTools console:
      var panel = UIView.library.Get<ZonedBuildingWorldInfoPanel>(typeof(ZonedBuildingWorldInfoPanel).Name); var checkBox = panel.component.Find<UICheckBox>("MakeHistorical"); checkBox.relativePosition = new Vector3(14f, 164f + 130f + 5f); Result:

       
      Now we just have to increase the height of the window a little bit. Execute this code in the ModTools console:
      var panel = UIView.library.Get<ZonedBuildingWorldInfoPanel>(typeof(ZonedBuildingWorldInfoPanel).Name); panel.component.height = 321f + 5f + 20f; Result:

       
      Now, we will put the code we just executed with the console into the loading hook of our mod:
      using ColossalFramework.UI; using ICities; using UnityEngine; namespace MakeHistorical { public class MakeHistoricalLoading : LoadingExtensionBase { private UICheckBox _makeHistoricalCheckBox; public override void OnLevelLoaded(LoadMode mode) { if (_makeHistoricalCheckBox != null) return; ZonedBuildingWorldInfoPanel panel = UIView.library.Get<ZonedBuildingWorldInfoPanel>(typeof(ZonedBuildingWorldInfoPanel).Name); UICheckBox checkBox = panel.component.AddUIComponent<UICheckBox>(); checkBox.width = panel.component.width; checkBox.height = 20f; checkBox.clipChildren = true; UISprite sprite = checkBox.AddUIComponent<UISprite>(); sprite.spriteName = "ToggleBase"; sprite.size = new Vector2(16f, 16f); sprite.relativePosition = Vector3.zero; checkBox.checkedBoxObject = sprite.AddUIComponent<UISprite>(); ((UISprite)checkBox.checkedBoxObject).spriteName = "ToggleBaseFocused"; checkBox.checkedBoxObject.size = new Vector2(16f, 16f); checkBox.checkedBoxObject.relativePosition = Vector3.zero; checkBox.label = checkBox.AddUIComponent<UILabel>(); checkBox.label.text = " "; checkBox.label.textScale = 0.9f; checkBox.label.relativePosition = new Vector3(22f, 2f); checkBox.name = "MakeHistorical"; checkBox.text = "Make Historical"; checkBox.relativePosition = new Vector3(14f, 164f + 130f + 5f); panel.component.height = 321f + 5f + 16f; _makeHistoricalCheckBox = checkBox; } } }
      Compile the mod (F6). If there are any compilation errors, use the error list in VS2017 to locate and fix the error (View > Error List)
      When the compilation was successful, run the game. Enable the mod in content manager (if your mod does not show up, you probably forgot to setup the post build script).
      Now create or load a city, open the building info window for a growable building. Et voila:

       
      Step 6: Processing Checkbox Events
      To process checkbox events, we will add a delegate to the CheckedChange event:
      public override void OnLevelLoaded(LoadMode mode) { ... checkBox.eventCheckChanged += (component, check) => { ushort buildingId = WorldInfoPanel.GetCurrentInstanceID().Building; if (check) { MakeHistoricalDataManager.Instance.AddBuildingId(buildingId); } else { MakeHistoricalDataManager.Instance.RemoveBuildingId(buildingId); } }; } Clicking the checkbox now triggers the data manager:

       
      Step 7: Monitoring the ZonedBuildingWorldInfoPanel with a Threading Hook
      There is another problem: The checkbox is not updated when you select a building. We will use a threading hook to update the checkbox:
      using ColossalFramework.UI; using ICities; namespace MakeHistorical { public class MakeHistoricalPanelMonitor : ThreadingExtensionBase { private ZonedBuildingWorldInfoPanel _panel; private UICheckBox _makeHistoricalCheckBox; private ushort _lastBuildingId = 0; // called every frame public override void OnUpdate(float realTimeDelta, float simulationTimeDelta) { if (!FindComponents()) return; if (_panel.component.isVisible) { ushort buildingId = WorldInfoPanel.GetCurrentInstanceID().Building; if (_lastBuildingId != buildingId) { // display the right checkbox state _makeHistoricalCheckBox.isChecked = MakeHistoricalDataManager.Instance.IsHistorical(buildingId); _lastBuildingId = buildingId; } } else { _lastBuildingId = 0; } } private bool FindComponents() { if (_panel != null && _makeHistoricalCheckBox != null) return true; _panel = UIView.library.Get<ZonedBuildingWorldInfoPanel>(typeof(ZonedBuildingWorldInfoPanel).Name); if (_panel == null) return false; _makeHistoricalCheckBox = _panel.component.Find<UICheckBox>("MakeHistorical"); return _makeHistoricalCheckBox != null; } } }  
      Step 8: Controlling Building Level Up
      It took quite some time to get to this point (UI and serialization are always very time consuming). The last missing piece is the ILevelUpExtension/LevelUpExtensionBase hook, which monitors and manipulates the level up behaviour of buildings. Probably the least complicated part of the mod:
      using ICities; namespace MakeHistorical { public class MakeHistoricalLevelUpMonitor : LevelUpExtensionBase { public override ResidentialLevelUp OnCalculateResidentialLevelUp(ResidentialLevelUp levelUp, int averageEducation, int landValue, ushort buildingID, Service service, SubService subService, Level currentLevel) { if (MakeHistoricalDataManager.Instance.IsHistorical(buildingID)) { levelUp.targetLevel = currentLevel; } return levelUp; } public override CommercialLevelUp OnCalculateCommercialLevelUp(CommercialLevelUp levelUp, int averageWealth, int landValue, ushort buildingID, Service service, SubService subService, Level currentLevel) { if (MakeHistoricalDataManager.Instance.IsHistorical(buildingID)) { levelUp.targetLevel = currentLevel; } return levelUp; } public override IndustrialLevelUp OnCalculateIndustrialLevelUp(IndustrialLevelUp levelUp, int averageEducation, int serviceScore, ushort buildingID, Service service, SubService subService, Level currentLevel) { if (MakeHistoricalDataManager.Instance.IsHistorical(buildingID)) { levelUp.targetLevel = currentLevel; } return levelUp; } public override OfficeLevelUp OnCalculateOfficeLevelUp(OfficeLevelUp levelUp, int averageEducation, int serviceScore, ushort buildingID, Service service, SubService subService, Level currentLevel) { if (MakeHistoricalDataManager.Instance.IsHistorical(buildingID)) { levelUp.targetLevel = currentLevel; } return levelUp; } } } The logic is very simple: When the building is historical, the target level is set to the current building level.
      And we are done! Buildings with the "Make Historical" checkbox enabled will no longer level up. The list of historical buildings is stored in the savegame.

      Happy Coding!
      Download Source
    • By boformer
      Right now I only have little time, and I'm not able to write new mods. But I want to share my knowlege about Cities: Skylines mod development with you!
      Mod Development Tutorials
       
    • By boformer
      In this tutorial, we will replicate the functionality of the Show Limits mod. Like in Tutorial 1, we will use the default alert window to display the limits. You will learn how to use ILSpy for reverse engineering, how to access singleton manager objects, how to work with building/tree instances and how to listen to keyboard shortcuts.
       
      Step 1: Exploring the game source code in ILSpy
      Download the latest version of ILSpy (select "Download Binaries"). ILSpy is an open source decompiler that allows you to take a look at the source code of the game and other mods. It's basically the opposite of a compiler:
      [compiled .dll file] → [DECOMPILER] → [.cs files containing raw C# code] The restored source code is not exactly the same as the original code. Names of variables defined in methods are lost, which makes the code harder to read. Some parts of the loading code are not readable (enumerators), but that won't bother us.
      Open the Assembly-CSharp.dll file in ILSpy (C:\Program Files (x86)\Steam\steamapps\common\Cities_Skylines\Cities_Data\Managed). On the left, expand the source tree:

      The tree contains all classes and structs of the game. Select one of them to view the source code. There are different types of classes, here are the most common ones:
      ...Info: Prefabs or other assets (see Tutorial 1 and 2) Building, Citizen, District, NetLane, NetNode, NetSegment, PropInstance, TransportLine, TreeInstance, Vehicle, ZoneBlock (structs): Instances of objects, managed by a simulation system. There is a limit how many instances of a certain type can exist. ...AI: AI behaviour attached to prefabs, calculating the behavior of object instances. ...Manager: A simulation system,  responsible for rendering, simulation and creation/deletion of instances ...Tool: Tool for interacting with the city ...Collection: A collection of prefabs or assets ...Properties: Properties for simulation systems, like colors, shaders and constants ...Panel: UI elements ...Wrapper: Implementation of the official modding API  
      The various manager classes are the key components of the game. Managers extend the Singleton<> class. The singleton pattern is a software design pattern that ensures that only one instance of a class exists. You can easily access a singleton in Cities: Skylines with the static instance field:
      string cityName = SimulationManager.instance.m_metaData.m_CityName; Debug.Log("Name of the city: " + cityName); Alternatively:
      Singleton<SimulationManager>.instance Tip: You can run these code snippets with the ModTools console (F7)
       
      Today we will take a look at the TreeManager and BuildingManager to display the number of trees and buildings.
      Tree Manager
      Select the TreeManager in ILSpy. After scrolling down a few lines in the source code, you will find the constant MAX_TREE_COUNT and the integer field m_treeCount:

      Outputting these numbers will lead to the desired result. We will go a step further and check how the m_treeCount field is calculated. Right click the m_treeCount item in the left sidebar and select "Analyze":

      The panel at the bottom displays which methods are reading the field, and which methods are assigning values to the field. For example, the AssetEditorChirpPanel and EditorChirpPanel are reading the field to display the number of trees in the asset/map editor.
      The field is modified by 3 methods of the TreeManager:
      CreateTree: When a new tree instance is placed, increment the value by 1. ReleaseTreeImplementation: When a tree instance is deleted, decrement the value by 1 Data.AfterDeserialize: After a save game is loaded, recalculate the tree count The last method is particularly interesting. Double click it to view the source code of the method:

      The method calls TreeManager.instance.m_trees.ItemCount() to calculate the number of trees.
      m_trees is a special kind of array list (Array16<TreeInstance>) that is used by the game to manage instances of trees, props, buildings etc. The list contains a fixed number of TreeInstance structs (262144 in case of trees). When a new tree is created, one of the unused items from the listt is activated and used to describe the state, position and type of a tree. A few lines above you can see how the game iterates through the list to modify the active items.
      Tip: You can also use the "Analyze" feature on methods and classes. It will help you to understand how the different components of the game are connected.
      Building Manager
      Now, select the BuildingManager on the left. You will notice that the BuildingManager contains the same kind of fields:
      const int MAX_BUILDING_COUNT: The max number of building instances int m_buildingCount: The current number of building instances Array16<Building> m_buildings: The array list containing the building instances  
      Step 2: Outputting the limits with ModTools
      Before writing our mod, we will create a ModTools script to see if everything works:
      int treeCount = TreeManager.instance.m_treeCount; int maxTreeCount = TreeManager.MAX_TREE_COUNT; Debug.Log("Number of trees: " + treeCount + " of " + maxTreeCount); int buildingCount = BuildingManager.instance.m_buildingCount; int maxBuildingCount = BuildingManager.MAX_BUILDING_COUNT; Debug.Log("Number of buildings: " + buildingCount + " of " + maxBuildingCount); Load or create a city and open the ModTools console (F7). In the bottom of the console, paste the script and press the "Run" button:

       
      Step 3: Project Setup
      Create a new project named "ShowLimits" in VS2017, following Method 2 in Tutorial 0 (working with a text editor is still possible in this tutorial, but not recommended)
      Your IUserMod implementation should look like this:
      using ICities; namespace ShowLimits { public class ShowLimitsMod : IUserMod { public string Name => "Show Limits"; public string Description => "Displays the number of buildings and trees in your city (Hotkey CTRL + I)"; } }  
      Step 4: Threading Hook & Hotkeys
      The IThreadingExtension/ThreadingExtensionBase is another hook provided by the official modding API. Classes implementing IThreadingExtension are invoked before, during and after every simulation tick (many times per second). It is important that the contained code is very light-weight (no IO operations, like reading configuration files, no object construction...).
      We will use the hook to check if the player is pressing they keyboard shortcut (CTRL + I).
      Create a new class called ShowLimitsThreading:
      using ColossalFramework.UI; using ICities; using UnityEngine; namespace ShowLimits { public class ShowLimitsThreading : ThreadingExtensionBase { private bool _processed = false; public override void OnUpdate(float realTimeDelta, float simulationTimeDelta) { if ((Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) && Input.GetKey(KeyCode.I)) { // cancel if they key input was already processed in a previous frame if (_processed) return; _processed = true; // compose message int treeCount = TreeManager.instance.m_treeCount; int maxTreeCount = TreeManager.MAX_TREE_COUNT; int buildingCount = BuildingManager.instance.m_buildingCount; int maxBuildingCount = BuildingManager.MAX_BUILDING_COUNT; string message = $"Trees: {treeCount} of {maxTreeCount}\nBuildings: {buildingCount} of {maxBuildingCount}"; // display message ExceptionPanel panel = UIView.library.ShowModal<ExceptionPanel>("ExceptionPanel"); panel.SetMessage("Show Limits", message, false); } else { // not both keys pressed: Reset processed state _processed = false; } } } }
      Now compile the mod (F6). If there are any compilation errors, use the error list in VS2017 to locate and fix the error (View > Error List)
      When the compilation was successful, run the game. Enable the mod in content manager (if your mod does not show up, you probably forgot to setup the post build script).
      Now create or load a city. Press Ctrl + I:

      Happy Coding!
      Download Source
       
      Next Part:
       
  • Recently Browsing   0 members

    No registered users viewing this page.