<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://planeshift.top-ix.org//pswiki/index.php?action=history&amp;feed=atom&amp;title=City_Manager</id>
	<title>City Manager - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://planeshift.top-ix.org//pswiki/index.php?action=history&amp;feed=atom&amp;title=City_Manager"/>
	<link rel="alternate" type="text/html" href="https://planeshift.top-ix.org//pswiki/index.php?title=City_Manager&amp;action=history"/>
	<updated>2026-09-14T16:02:08Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.1</generator>
	<entry>
		<id>https://planeshift.top-ix.org//pswiki/index.php?title=City_Manager&amp;diff=25787&amp;oldid=prev</id>
		<title>Talad: Created page with &quot;= CityManager admin guide =  CityManager uses database tables to define cities, their manager NPCs, development tiers, required resources, and buildable assets.  Apply configuration changes while the server is stopped, then restart it and reconnect the client. CityManager loads its configuration at startup and updates progress during play.  == 1. Define the city and manager NPC ==  Create or choose an existing, normally spawned NPC in the &lt;code&gt;characters&lt;/code&gt; table. A...&quot;</title>
		<link rel="alternate" type="text/html" href="https://planeshift.top-ix.org//pswiki/index.php?title=City_Manager&amp;diff=25787&amp;oldid=prev"/>
		<updated>2026-09-13T16:19:05Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;= CityManager admin guide =  CityManager uses database tables to define cities, their manager NPCs, development tiers, required resources, and buildable assets.  Apply configuration changes while the server is stopped, then restart it and reconnect the client. CityManager loads its configuration at startup and updates progress during play.  == 1. Define the city and manager NPC ==  Create or choose an existing, normally spawned NPC in the &amp;lt;code&amp;gt;characters&amp;lt;/code&amp;gt; table. A...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;= CityManager admin guide =&lt;br /&gt;
&lt;br /&gt;
CityManager uses database tables to define cities, their manager NPCs, development tiers, required resources, and buildable assets.&lt;br /&gt;
&lt;br /&gt;
Apply configuration changes while the server is stopped, then restart it and reconnect the client. CityManager loads its configuration at startup and updates progress during play.&lt;br /&gt;
&lt;br /&gt;
== 1. Define the city and manager NPC ==&lt;br /&gt;
&lt;br /&gt;
Create or choose an existing, normally spawned NPC in the &amp;lt;code&amp;gt;characters&amp;lt;/code&amp;gt; table. Assign its &amp;lt;code&amp;gt;characters.id&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;city_info.npc_manager_id&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The NPC becomes a city manager automatically when it loads. No separate CityManager flag or dialogue is required by this module. Use a different NPC for each city: an NPC is associated with only the first matching city.&lt;br /&gt;
&lt;br /&gt;
Add one row to &amp;#039;&amp;#039;&amp;#039;city_info&amp;#039;&amp;#039;&amp;#039;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Column&lt;br /&gt;
! What to enter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;&lt;br /&gt;
| Unique positive city ID, referenced by the other city tables.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt;&lt;br /&gt;
| City display name.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;location&amp;lt;/code&amp;gt;&lt;br /&gt;
| City center as integer &amp;lt;code&amp;gt;x,y,z&amp;lt;/code&amp;gt; coordinates in Unreal world units (centimeters), for example &amp;lt;code&amp;gt;205238,-310363,11061&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;influence_range&amp;lt;/code&amp;gt;&lt;br /&gt;
| Base radius in meters. The effective radius is this value multiplied by the current Infrastructure tier. Tier 0 gives a zero radius.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;npc_manager_id&amp;lt;/code&amp;gt;&lt;br /&gt;
| The manager NPC&amp;#039;s &amp;lt;code&amp;gt;characters.id&amp;lt;/code&amp;gt;. The NPC must actually load into the world.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;citizens&amp;lt;/code&amp;gt;&lt;br /&gt;
| Base population. The displayed population is calculated from this value and the current tiers.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;happiness&amp;lt;/code&amp;gt;&lt;br /&gt;
| Normally &amp;lt;code&amp;gt;0.5&amp;lt;/code&amp;gt;. The server recalculates happiness from the current tiers, overriding this loaded value.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;period_start_date&amp;lt;/code&amp;gt;&lt;br /&gt;
| Leave &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt; for a new city. The current module does not implement a ranking-period reset using this field.&lt;br /&gt;
|-&lt;br /&gt;
| Six &amp;lt;code&amp;gt;cat_*&amp;lt;/code&amp;gt; columns listed below&lt;br /&gt;
| Current achieved tier: normally &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; for a new city, or &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt; for an established city.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Players must target the manager and be within 1,000 Unreal units (10 meters) to request the city information screen.&lt;br /&gt;
&lt;br /&gt;
== 2. Define categories and tier descriptions ==&lt;br /&gt;
&lt;br /&gt;
Use these category IDs in the development tables:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Category ID&lt;br /&gt;
! Category&lt;br /&gt;
! Current tier column in city_info&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| Infrastructure&lt;br /&gt;
| &amp;lt;code&amp;gt;cat_infrastructure&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Hospitality&lt;br /&gt;
| &amp;lt;code&amp;gt;cat_hospitality&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| Crafting&lt;br /&gt;
| &amp;lt;code&amp;gt;cat_crafting&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| Faith&lt;br /&gt;
| &amp;lt;code&amp;gt;cat_faith&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| Education&lt;br /&gt;
| &amp;lt;code&amp;gt;cat_education&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Agriculture&lt;br /&gt;
| &amp;lt;code&amp;gt;cat_agriculture&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The data model reserves &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt; to hide an unavailable category. However, the current population and happiness calculations still include negative tier values. Avoid &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt; tiers.&lt;br /&gt;
&lt;br /&gt;
Add one row per city, category, and target tier to &amp;#039;&amp;#039;&amp;#039;city_tier_def&amp;#039;&amp;#039;&amp;#039;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Column&lt;br /&gt;
! What to enter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;city_id&amp;lt;/code&amp;gt;&lt;br /&gt;
| The city&amp;#039;s &amp;lt;code&amp;gt;city_info.id&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;city_category&amp;lt;/code&amp;gt;&lt;br /&gt;
| Category ID from 1 to 6.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tier&amp;lt;/code&amp;gt;&lt;br /&gt;
| The achieved tier being described, normally 1, 2, or 3.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;description&amp;lt;/code&amp;gt;&lt;br /&gt;
| Player-facing explanation of that tier&amp;#039;s benefits.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Descriptions are display text. Adding a benefit to a description does not implement that benefit.&lt;br /&gt;
&lt;br /&gt;
The module calculates:&lt;br /&gt;
* Population: base population plus 10% of the base for each summed tier in Infrastructure, Crafting, and Agriculture.&lt;br /&gt;
* Happiness: &amp;lt;code&amp;gt;0.5 + round((Hospitality + Faith + Education) × 0.055, 2)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== 3. Define resources required for each tier ==&lt;br /&gt;
&lt;br /&gt;
Each resource must have an existing definition in &amp;#039;&amp;#039;&amp;#039;item_stats&amp;#039;&amp;#039;&amp;#039;. CityManager obtains the resource name and image from that definition.&lt;br /&gt;
&lt;br /&gt;
Add one row per required resource to &amp;#039;&amp;#039;&amp;#039;city_resource_tiers&amp;#039;&amp;#039;&amp;#039;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Column&lt;br /&gt;
! What to enter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;city_id&amp;lt;/code&amp;gt;&lt;br /&gt;
| The city&amp;#039;s &amp;lt;code&amp;gt;city_info.id&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tier&amp;lt;/code&amp;gt;&lt;br /&gt;
| The &amp;#039;&amp;#039;&amp;#039;target tier&amp;#039;&amp;#039;&amp;#039;: 1 pays for the upgrade from 0 to 1; 2 pays for 1 to 2; 3 pays for 2 to 3.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;city_category&amp;lt;/code&amp;gt;&lt;br /&gt;
| Category ID from 1 to 6.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;item_stats_id&amp;lt;/code&amp;gt;&lt;br /&gt;
| The required resource&amp;#039;s &amp;lt;code&amp;gt;item_stats.id&amp;lt;/code&amp;gt;. This references an item definition, not an individual item instance.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;need&amp;lt;/code&amp;gt;&lt;br /&gt;
| Positive whole-number quantity required.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;storage&amp;lt;/code&amp;gt;&lt;br /&gt;
| Amount already donated. Initialize to &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;; the server updates it during play.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Several rows for the same city, category, and tier mean &amp;#039;&amp;#039;&amp;#039;all those resources are required&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Keep each combination of &amp;lt;code&amp;gt;city_id&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;city_category&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;tier&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;item_stats_id&amp;lt;/code&amp;gt; unique. The supplied schema does not enforce this.&lt;br /&gt;
&lt;br /&gt;
Define resource costs for every supported target tier of each enabled category. Missing rows should not be used to disable an upgrade: the current server upgrade check can succeed without matching requirements and does not itself enforce a tier-3 cap.&lt;br /&gt;
&lt;br /&gt;
=== Example ===&lt;br /&gt;
&lt;br /&gt;
Assuming city ID &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt; already exists, these rows make Infrastructure tier 1 require 10 units of item 8072 and 2,000 units of item 86:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
INSERT INTO city_resource_tiers&lt;br /&gt;
    (city_id, tier, city_category, item_stats_id, need, storage)&lt;br /&gt;
VALUES&lt;br /&gt;
    (10, 1, 1, 8072, 10, 0),&lt;br /&gt;
    (10, 1, 1,   86, 2000, 0);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO city_tier_def&lt;br /&gt;
    (city_id, city_category, tier, description)&lt;br /&gt;
VALUES&lt;br /&gt;
    (10, 1, 1,&lt;br /&gt;
     &amp;#039;City influence reaches the base radius; population gains 10% of its base.&amp;#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify the item IDs in your database before using this example. Then add costs and descriptions for tiers 2 and 3 and repeat for the other enabled categories.&lt;br /&gt;
&lt;br /&gt;
=== Donations and upgrades ===&lt;br /&gt;
&lt;br /&gt;
* The server checks for an upgrade after a contribution.&lt;br /&gt;
* Every required resource must have &amp;lt;code&amp;gt;storage == need&amp;lt;/code&amp;gt;. Avoid overfilling storage.&lt;br /&gt;
* On upgrade, the completed tier&amp;#039;s resource storage resets to zero and the corresponding &amp;lt;code&amp;gt;city_info.cat_*&amp;lt;/code&amp;gt; value increases.&lt;br /&gt;
* Preloading storage alone does not trigger an upgrade at startup.&lt;br /&gt;
* For money, use the item definition named exactly &amp;lt;code&amp;gt;Tria&amp;lt;/code&amp;gt;. The amount is taken from the player&amp;#039;s wallet in trias. The seed scripts use item ID 86; verify this locally.&lt;br /&gt;
* Ordinary donations match the item definition and name, exclude equipped items, and require a single sufficient stack per submitted donation.&lt;br /&gt;
&lt;br /&gt;
== 4. Optional buildable assets ==&lt;br /&gt;
&lt;br /&gt;
Assets use separate definitions and recipes:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table&lt;br /&gt;
! What to add&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;city_asset_def&amp;lt;/code&amp;gt;&lt;br /&gt;
| One row per asset: unique &amp;lt;code&amp;gt;asset_id&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;asset_category&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;item_stats_id&amp;lt;/code&amp;gt; for the finished asset&amp;#039;s name and description.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;city_asset_resources_def&amp;lt;/code&amp;gt;&lt;br /&gt;
| One row per recipe ingredient: &amp;lt;code&amp;gt;asset_id&amp;lt;/code&amp;gt;, resource &amp;lt;code&amp;gt;item_stats_id&amp;lt;/code&amp;gt;, and positive &amp;lt;code&amp;gt;need&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;city_asset_mapping&amp;lt;/code&amp;gt;&lt;br /&gt;
| Availability in a city: &amp;lt;code&amp;gt;city_id&amp;lt;/code&amp;gt;, development &amp;lt;code&amp;gt;category&amp;lt;/code&amp;gt; (1–6), required &amp;lt;code&amp;gt;tier&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;asset_id&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use these values for &amp;#039;&amp;#039;&amp;#039;city_asset_def.asset_category&amp;#039;&amp;#039;&amp;#039;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Asset category ID&lt;br /&gt;
! Asset group&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| Defense&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Army&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Siege&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| Magic&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The SQL schema comment saying asset categories are 1–4 is outdated.&lt;br /&gt;
&lt;br /&gt;
Asset categories and development categories have different purposes. For example, an asset with &amp;lt;code&amp;gt;asset_category = 7&amp;lt;/code&amp;gt; and a mapping with &amp;lt;code&amp;gt;category = 1, tier = 2&amp;lt;/code&amp;gt; is a Defense asset associated with Infrastructure tier 2.&lt;br /&gt;
&lt;br /&gt;
Add the asset&amp;#039;s ingredient rows separately and avoid duplicate mappings or recipe ingredients.&lt;br /&gt;
&lt;br /&gt;
== 5. Progress tables and decay ==&lt;br /&gt;
&lt;br /&gt;
For a new city, normally leave these tables without rows for that city. The server creates progress during play. The tables themselves must still exist.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table&lt;br /&gt;
! Fields&lt;br /&gt;
! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;city_consume_status&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;city_id, tier, city_category, consumption&amp;lt;/code&amp;gt;&lt;br /&gt;
| Remaining tier lifetime, starting at 1 and decreasing toward 0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;city_assets_resource_storage&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;city_id, asset_id, item_stats_id, storage&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ingredients donated toward an unfinished asset.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;city_assets_storage&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;city_id, asset_id, quantity&amp;lt;/code&amp;gt;&lt;br /&gt;
| Completed asset counts.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;city_ranking&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;city_id, guild_id, character_id, points&amp;lt;/code&amp;gt;&lt;br /&gt;
| Contributor scores.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Tier-resource donations are stored directly in &amp;lt;code&amp;gt;city_resource_tiers.storage&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Decay is configured globally in &amp;lt;code&amp;gt;Config/DefaultServerConfig.ini&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[/script/PSUnreal.CityManager]&lt;br /&gt;
cityConsumeTime=60&lt;br /&gt;
cityConsumeAmount=0.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These checked-in settings schedule a tick every 60 seconds. Each tick decreases an existing current-tier consumption entry by 0.1. A missing entry is first created at 1.&lt;br /&gt;
&lt;br /&gt;
When consumption reaches zero or below, the category drops one tier. This is a remaining-lifetime counter, rather than a periodic subtraction of individual stored ingredients.&lt;br /&gt;
&lt;br /&gt;
== 6. Verify the setup ==&lt;br /&gt;
&lt;br /&gt;
# Restart the server and reconnect the client.&lt;br /&gt;
# Check startup logs for invalid city, item, or asset references.&lt;br /&gt;
# Target the manager within 10 meters and open the city information screen.&lt;br /&gt;
# Verify the city name, categories, next-tier costs, and descriptions.&lt;br /&gt;
# Make a donation and complete one tier. Confirm that its tier increases and its resource storage resets.&lt;br /&gt;
# If assets are configured, verify their required-tier availability and recipes in the client.&lt;br /&gt;
&lt;br /&gt;
This guide is based on &amp;lt;code&amp;gt;Source/PSUnreal/server/citymanager.cpp&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;citymanager.h&amp;lt;/code&amp;gt;, NPC registration in &amp;lt;code&amp;gt;pscharacter.cpp&amp;lt;/code&amp;gt;, and the schema in &amp;lt;code&amp;gt;Scripts/psunreal_mysql_20260724.sql&amp;lt;/code&amp;gt;. It has not been validated against a running database.&lt;br /&gt;
&lt;br /&gt;
The older &amp;lt;code&amp;gt;Scripts/UPDATE_SCHEMA_PSUNREAL_CITY.sql&amp;lt;/code&amp;gt; omits &amp;lt;code&amp;gt;city_tier_def&amp;lt;/code&amp;gt;. The seed data is an example and does not provide a complete setup for every city.&lt;/div&gt;</summary>
		<author><name>Talad</name></author>
	</entry>
</feed>