Merge branch 'develop'

This commit is contained in:
Simon Brooke 2024-06-10 15:53:10 +01:00
commit e6d892a594
186 changed files with 1151393 additions and 636 deletions

6
.gitignore vendored
View file

@ -54,3 +54,9 @@ src/cc/journeyman/the_great_game/cloverage.clj
.DS_Store
.portal/
# Excluding third party resources from the public repo;
# probably ought to list them in the README files.
resources/jme3/images/
resources/jme3/textures/
resources/polyhaven/textures/

View file

View file

@ -14,3 +14,5 @@ This doesn't work and isn't ever likely to fully work: it's way too ambitious fo
Copyright (c) 2019 Simon Brooke; licenced under the
[GNU General Public Licence](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html), either version 2 or, at your option, any later version.
Some assets from [jMonkeyEngine](https://jmonkeyengine.org/) examples are currently included in this repository; they are under [a BSD-style licence](https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/LICENSE.md).

176
doc/3D-formats.md Normal file
View file

@ -0,0 +1,176 @@
# 3D file formats
I'm going to be doing a lot with programatically manipulated models. Therefore there's a benefit to me in using a file format which is human-readable, and also easily parsed. Compactness is also a virtue, but it's a virtue I can achieve by compressing human readable files, I think.
Loading time is an issue, but I will be loading relatively few models and manipulating them in memory to produce large numbers of variants, rather than loading a new model for every asset I wish to place. So both from the point of view of total disk space and from the point of view of performance, I think that formats which are optimised more towards my needs as a developer than to raw performance or storage size are probably justified.
Obviously jMonkeyEngine's own `.j3o` format is something I can parse -- because I have the native jMonkeyEngine libraries to do it -- but it's not something I can inspect or hand edit, so I'm unwilling at this stage to use it. As I understand it, it's a file of serialised Java objects, which, if so, would make it relatively efficient to load.
## XML formats
XML formats are easy to parse; they're also reasonably easy to edit both as text files and as structured files. So my preference is to use them as a starting point for search. The obvious XML formats are
1. [3DXML](https://en.wikipedia.org/wiki/3DXML), a proprietary format owned by Dassault Systèmes;
2. [Collada](https://www.khronos.org/collada/), an open format apparently seen primarily as an unlossy interchange format between 3d applications;
3. [X3D](https://www.web3d.org/x3d/what-x3d/), an open format seen as the successor to (and much more prolix than) VRML;
4. Ogre 3D, a format designed for the [Ogre 3D game engine](https://www.ogre3d.org/) and now widely used in the jMonkeyEngine community, but for which I can find no documentation.
## JSON-based formats
JSON is also easy to parse and to edit; the [glTF 2.0](https://www.khronos.org/gltf/) standard, in its JSON/ASCII representation, is such a format.
## Other text formats
[VRML](https://en.wikipedia.org/wiki/VRML) isn't either XML or JSON, but it looks reasonably easy to parse.
## Features
| Name | XML | JSON | Blender | jME3 | Notes |
| -------------------------------------------- | ------- | ------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| [3DXML](https://en.wikipedia.org/wiki/3DXML) | ✓ | | [Unsupported](https://blenderartists.org/t/3dxml-importer/469975/2) | No | Proprietary; apparently, engineering oriented |
| [Collada](https://www.khronos.org/collada/) | ✓ | | Built in importer/exporter | [No](https://hub.jmonkeyengine.org/t/collada-io/46406) | Prolix, but sort-of interpretable and manageable. |
| [X3D](https://www.web3d.org/x3d/what-x3d/) | ✓ | | Built in importer/exporter | No | |
| [Ogre 3D](https://www.ogre3d.org/) | ✓ | | [Unsupported](https://github.com/OGRECave/blender2ogre) | [built in importer](https://javadoc.jmonkeyengine.org/v3.6.1-stable/com/jme3/scene/plugins/ogre/package-summary.html) | |
| [glTF 2.0](https://www.khronos.org/gltf/) | | ✓ | Built in importer/exporter | [built in importer](https://javadoc.jmonkeyengine.org/v3.6.1-stable/com/jme3/scene/plugins/gltf/package-summary.html) | On inspection, the glTF 2.0 files generated by Blender are thoroughly inscrutable. Although they are technically text files, they're essentially very thin wrappers around ascii-coded binary blobs. This doesn't look usable to me. |
| [VRML](https://en.wikipedia.org/wiki/VRML) | | | Apparently accepted by the X3D importer; no exporter | No | I couldn't make import of a sample file into Blender work. The import completed with no errors, but no objects appeared in the scene. |
## Discussion
I did not investigate 3DXML, because I'm not going to sign up to even a free licence from an armaments company.
Of the rest: I'm pretty disappointed.
### glTF
**glTF** might as well be a binary format; it's unusable for my purposes.
### X3D
**X3D** export of the simple cube from Blender results in a file which is readable, but which does not have explicit vertices or edges. Instead it has an attribute whose value is a string representation of a sequence of 24 numbers:
```xml
<Coordinate DEF="coords_ME_Cube"
point="1.000000 1.000000 1.000000 1.000000 1.000000 -1.000000 1.000000 -1.000000 1.000000 1.000000 -1.000000 -1.000000 -1.000000 1.000000 1.000000 -1.000000 1.000000 -1.000000 -1.000000 -1.000000 1.000000 -1.000000 -1.000000 -1.000000 "/>
```
I'm confidently assuming that that sequence is expected to be read as a set of six triples, each triple representing a vertex with `x, y, z` coordinates; but it's not at all clear to me how edges and faces are encoded.
Furthermore, when you reimport an X3D file exported by Blender back into Blender you get nothing visible (and no error message). This is exactly the same as what you get when you import a VRML file, which does not raise confidence.
### Collada
**Collada** is a little better in that it explicitly says how many numbers are in the array, and does not present them as an attribute but as data; additionally, it has information on how to decode that data into tuples:
```xml
<source id="Cube-mesh-positions">
<float_array id="Cube-mesh-positions-array" count="24">1 1 1 1 1 -1 1 -1 1 1 -1 -1 -1 1 1 -1 1 -1 -1 -1 1 -1 -1 -1</float_array>
<technique_common>
<accessor source="#Cube-mesh-positions-array" count="8" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
```
and the **vertices** are declared as being the points in this array:
```xml
<vertices id="Cube-mesh-vertices">
<input semantic="POSITION" source="#Cube-mesh-positions"/>
</vertices>
```
but again there's nothing obvious to indicate which vertices are joined by **edges**. There is an array of six normals, which presumably imply the faces of the cube, but that's a little sketchy. There are also **triangles**, declared as follows:
```xml
<triangles material="Material-material" count="12">
<input semantic="VERTEX" source="#Cube-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Cube-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Cube-mesh-map-0" offset="2" set="0"/>
<p>4 0 0 2 0 1 0 0 2 2 1 3 7 1 4 3 1 5 6 2 6 5 2 7 7 2 8 1 3 9 7 3 10 5 3 11 0 4 12 3 4 13 1 4 14 4 5 15 1 5 16 5 5 17 4 0 18 6 0 19 2 0 20 2 1 21 6 1 22 7 1 23 6 2 24 4 2 25 5 2 26 1 3 27 3 3 28 7 3 29 0 4 30 2 4 31 3 4 32 4 5 33 0 5 34 1 5 35</p>
</triangles>
```
H'mmm... Twelve triangles makes sense for six square faces, but there are 108 numbers in that `<p>` element, which is eighteen numbers per triangle; and since the highest number is 35, they're not indices into either the `Cube-mesh-vertices` (8) or the `Cube-mesh-normals` (6) arrays, so that implies they are indices into `Cube-mesh-map-0`, which *does* have 36 entries...
```xml
<source id="Cube-mesh-map-0">
<float_array id="Cube-mesh-map-0-array" count="72">0.875 0.5 0.625 0.75 0.625 0.5 0.625 0.75 0.375 1 0.375 0.75 0.625 0 0.375 0.25 0.375 0 0.375 0.5 0.125 0.75 0.125 0.5 0.625 0.5 0.375 0.75 0.375 0.5 0.625 0.25 0.375 0.5 0.375 0.25 0.875 0.5 0.875 0.75 0.625 0.75 0.625 0.75 0.625 1 0.375 1 0.625 0 0.625 0.25 0.375 0.25 0.375 0.5 0.375 0.75 0.125 0.75 0.625 0.5 0.625 0.75 0.375 0.75 0.625 0.25 0.625 0.5 0.375 0.5</float_array>
<technique_common>
<accessor source="#Cube-mesh-map-0-array" count="36" stride="2">
<param name="S" type="float"/>
<param name="T" type="float"/>
</accessor>
</technique_common>
</source>
```
which is six entries per face. Which sort of makes sense. But the numbers make no obvious sense to me. There are nine distinct values:
```clojure
user=> (def s (set [0.875 0.5 0.625 0.75 0.625 0.5 0.625 0.75 0.375 1 0.375 0.75 0.625 0 0.375 0.25 0.375 0 0.375 0.5 0.125 0.75 0.125 0.5 0.625 0.5 0.375 0.75 0.375 0.5 0.625 0.25 0.375 0.5 0.375 0.25 0.875 0.5 0.875 0.75 0.625 0.75 0.625 0.75 0.625 1 0.375 1 0.625 0 0.625 0.25 0.375 0.25 0.375 0.5 0.375 0.75 0.125 0.75 0.625 0.5 0.625 0.75 0.375 0.75 0.625 0.25 0.625 0.5 0.375 0.5]))
#'user/s
user=> s
#{0 0.125 0.25 0.5 0.625 0.375 0.75 0.875 1}
user=> (sort s)
(0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1)
```
But there's no obvious pattern to how frequently these values occur:
```clojure
user=> (map (fn [i] (count (filter (fn [j] (= i j)) all-values))) s)
(3 3 6 12 15 15 12 3 3)
```
So... it's not obvious to me how I extract a piece of solid geometry, namely a cube with sides of length 2, centred on the origin, from this data. I know it can be done, because when Blender reimports the file it not only renders a cube but recognises it as a cube; but it isn't trivial.
### Ogre 3D
**Ogre 3D** is a lot clearer. Here is (part of) its attempt at saving the cube:
```xml
<mesh>
<sharedgeometry vertexcount="24">
<vertexbuffer colours_diffuse="False" normals="true" positions="true" tangent_dimensions="0" tangents="False" texture_coords="1">
<vertex>
<position x="1.000000" y="1.000000" z="-1.000000"/>
<normal x="0.000000" y="1.000000" z="-0.000000"/>
<texcoord u="0.625000" v="0.500000"/>
</vertex>
<vertex>
<position x="-1.000000" y="1.000000" z="1.000000"/>
<normal x="0.000000" y="1.000000" z="-0.000000"/>
<texcoord u="0.875000" v="0.250000"/>
</vertex>
...
</vertexbuffer>
</sharedgeometry>
<submeshes>
<submesh material="Material" operationtype="triangle_list" use32bitindexes="False" usesharedvertices="true">
<faces count="12">
<face v1="0" v2="1" v3="2"/>
<face v1="3" v2="4" v3="5"/>
...
</faces>
</submesh>
</submeshes>
<submeshnames>
<submesh index="0" name="Material"/>
</submeshnames>
</mesh>
```
Nothing in this explicitly says it's a cube. But where we have two triangles with a common edge and a common normal, we know they form part of the same face; and, given that each of the distinct normals are either at right angles to, or in opposition to, each of the others, the boxiness is easily inferred. Finally, given all the edges are of the same length, we have a cube.
Although the [Ogre import/export add on](https://github.com/OGRECave/blender2ogre) is not supported by Blender, an exported cube can be successfully reimported into Blender.
The only documentation for Ogre 3D XML that I can find is [two DTDs here](https://github.com/OGRECave/ogre/tree/master/Tools/XMLConverter/docs), but, in fact, that is what I most need.
## Summary
Generally, this is disappointing. I may need to rethink my approach. But, although I was initially prejudiced against Ogre 3D because of its relative obscurity and lack of user-oriented documentation, it is probably the best of the bunch.

View file

@ -1,10 +1,12 @@
# Architecture
OK, the basic idea is this
Everything (every game object, including the world) is a map.
Every object as an :id property; every :id property is distinct.
There is a master map - the `oblist` which contains every object, keyed by its :id.
There is a master map - the `oblist` which contains every object, keyed by its :id. (Actually, there probably can't be such a map in working memory, because there will be too many objects. There will be such a map in the database -- but still keyed by :id).
Every object has a :run function, which returns either a new copy of itself or nil, and does not have side effects.

View file

@ -17,7 +17,7 @@ A `gossip` is an `actor` who exchanges news with other `actors`, even when the p
1. `innkeepers` (and possibly some others) are `gossips` who do not move; rather, they gather information from gossips who do move, and all `non-player characters` local to the are deemed to know everything that their local `innkeeper` knows;
2. `merchants` (and possibly some others) are `gossips` who do move from place to place, and thus transfer news.
See [the spread of knowledge in a large game world](The-spread-of-knowledge-in-large-game.html).
See [the spread of knowledge in a large game world](The-spread-of-knowledge-in-a-large-game-world.html).
#### Heightmap

View file

@ -4,8 +4,19 @@ Work by other people which is relevant to what I'm doing, and which I should stu
## Modelling the natural environment
### Forests
1. [Synthetic Silviculture: Multi-scale Modeling of Plant Ecosystems](https://storage.googleapis.com/pirk.io/projects/synthetic_silviculture/index.html) &mdash; see also [this video](https://youtu.be/8YOpFsZsR9w).
### Water
1. [Effective Water Simulation from Physical Models](https://developer.nvidia.com/gpugems/gpugems/part-i-natural-effects/chapter-1-effective-water-simulation-physical-models)
2. [Modelling Ocean Water](https://people.computing.clemson.edu/~jtessen/reports/papers_files/coursenotes2004.pdf)
## Systemic games
1. [This video](https://youtu.be/SnpAAX9CkIc) is thought provoking with excellent examples.
## Procedural animation
1. [This video](https://youtu.be/LNidsMesxSE) builds really impressive character animation on extremely simple foundations. I'm not saying this is easy, but it looks doable.

View file

@ -1,7 +0,0 @@
# Game-engine integration (unfinished)
To build a game using these ideas we need a lot of things that are well understood and already implemented: rendering a world, moving models of characters in a world, and so on. This collection of technologies which allow us to realise an interactive realisation of a world is typically called a game engine.
It's my intention that the bits that I add to the mix should be open source in the hard sense of that phrase, fully free software released under GPL. They cannot therfore be directly linked to a proprietary game engine.
But the current state of play is that the best and easiest to work with game engines are not open source; and while I could build a demo game using, for example, the [Godot engine](https://godotengine.org/) or [jMonkeyEngine](https://jmonkeyengine.org/) the result wouldn't be as compelling and *I believe* the effort would be more considerable than if I use [Unreal Engine](https://www.unrealengine.com/en-US), which is my current plan.

View file

@ -4,7 +4,7 @@
The Great Game exists as a project on two levels. One one level, it's a framework for building algorithms to build much more vibrant, and thus enjoyable game worlds; at another level, it's about building a particular world, in which I want to tell stories.
The world in which I want to tell stories is a world which is based roughly on late bronze age to medieval Europe. It's a world in which the region known as 'The Coast' -- the southern littoral of the continent -- had been a mostly-peaceful matrideic dispersed agrarian tribal society, which had been invaded some hundreds of years past by a warrior tribe with substantially better military technology.
The world in which I want to tell stories is a world which is based roughly on late bronze age to medieval Europe. It's a world in which the region known as 'The Coast' &mdash; the southern littoral of the continent &mdash; had been a mostly-peaceful matrideic dispersed agrarian tribal society, which had been invaded some hundreds of years past by a warrior tribe with substantially better military technology.
These warrior tribesmen have settled down as local tyrants or robber barons, parasitising on the indigenous communities, and have evolved into an aristocratic ('Ariston') class. In the meantime, a mercantile class has grown up and established important long distance overland trade routes; and significant towns (called 'cities', but of only at most a few tens of thousand inhabitants) have grown up around markets.

View file

@ -40,6 +40,75 @@ If we're going to represent a society in which public sex is normal, then we're
By 'eroticised', I'm meaning deliberately intended to trigger sexual feelings in the audience &mdash; which, if the player character is present, includes the player.
### Breeding strategies for non-player characters
In order to model population growth, I need to model when two NPCs will have sex; I need to model (roughly) when two NPCs will choose to have sex.
This is different for female NPCs to male NPCs (and female NPCs will be much more cautious, because of the risk/cost of pregnancy), so let's consider each in turn.
**Note that** sex happens if and only if the conditions for both the female partner and the male partner are met.
**Note that** we're considering heterosexual sex only here because what I'm currently modelling is population growth, and only heterosexual sex leads to pregnancy.
#### Generalised breeding strategy for a female NPC
A female NPC will have sex with a male NPC:
1. Long term relationship
1. Her life goal is `:ancestor`;
2. His life goal is either `:ancestor` or `:citizen`;
3. Her attitude towards him is +2 or above;
4. They reside in the same dwelling, *or* one or other of them is of no fixed abode (in which case they will reside in the same dwelling);
5. All other levels in her hierarchy of needs are currently satisfied.
2. Passion
1. His attitude towards her is +4, and
2. Her attitude towards him is also +4;
3. All other levels in her hierarchy of needs are currently satisfied.
3. Social climbing
1. Her life goal is `:climber` and
2. His social rank is two or more higher than hers (counting `:bonnet-laird` as above `:master`);
3. All other levels in her hierarchy of needs are currently satisfied.
4. Transactional
1. Need
1. She is hungry and broke; and
2. He has surplus food and/or money.
2. Coercion
1. He has something she urgently wants (the example I'm thinking of is he has abducted a child);
3. Sex work
1. Her life goal is `:hoarder`, and he has surplus money; or
2. It's possible I make sex work an actual career choice -- a craft of its own.
5. Rape
1. If she is a slave and he is her owner;
2. If he has defeated her in a fight;
3. If she assesses that he will defeat her in an impending fight;
4. Possibly, to distrct him from doing worse things to people she is protecting (e.g. children)
#### Generalised breeding strategy for a male NPC
1. Ancestor
1. His life goal is `:ancestor`; and
2. His attitude towards her is +2 or above;
3. All other levels in his hierarchy of needs are currently satisfied.
2. Long term relationship
1. His life goal is `:ancestor` or `:citizen`;
2. Her life goal is `:ancestor` or `:citizen`;
3. His attitude towards her is +2 or above;
4. They reside in the same dwelling, *or* one or other of them is of no fixed abode (in which case they will reside in the same dwelling);
5. All other levels in his hierarchy of needs are currently satisfied.
3. Dynastic
1. His life goal is `:conqueror`; and
2. Her social rank is `:ariston` or above;
3. She has no other existing long term sexual relationship;
4. All other levels in his hierarchy of needs are currently satisfied.
4. Social climbing
1. His life goal is `:climber`; and
2. Her social rank is at least one higher than his;
3. All other levels in his hierarchy of needs are currently satisfied.
5. Casual
1. His attitude towards her is +1 or above;
2. All other levels in his hierarchy of needs are currently satisfied.
## Sexual violence between non-player characters
In a world in which there are characters who are thuggish, who seek to dominate, terrorise and subdue other characters, whether those characters are outlaws or soldiers or aristocrats, to pretend that rape would not be used as a means to dominate, terrorise or subdue is… bowdlerisation. It's unrealistic, and it's a morally indefensible choice.

View file

@ -27,7 +27,7 @@ Hybrids are in effect chains of quests: do this task in order to get this precon
My understanding is that what Wikipedia means by a 'syntax quest' is what one would normally call a puzzle.
An escort quest is typically a request to take a specified non-player character safely through a dangerous area.
An escort quest is typically a request to take a specified non-player character safely through a dangerous area. It is thus very similar to a delivery quest, except that you are escorting a character rather than delivering an item.
Combo quests are not, in my opinion, particularly relevant to the sorts of game we're discussing here.

View file

@ -0,0 +1,5 @@
# Pseudo object inheritance
This is simply to document how I'm doing type inheritance for game objects, since Clojure does not provide type inheritance for records and I'm currently building game objects on Clojure records.
It's possible that I should instead build game objects on Java beans, which do have type (class) inheritance, and would work transparently; however, that isn't my current approach.

View file

@ -53,8 +53,6 @@ Most craft skills &mdash; especially in the learning phase &mdash; are not like
One of the most enjoyable aspects of The Witcher 3 &mdash; still my go-to game for ideas I want to improve on &mdash; is simply travelling through the world. Although fast travel is possible I find I rarely use it, and a journey which takes fifteen minutes of real world wall clock time can be enjoyable in and of itself. This is, of course, a credit to the beautiful way the world is realised.
(It's worth noting that [Kenshi](https://lofigames.com/), a game I'm coming to greatly admire, does not allow fast travel at all, but has an equivalent of 'cruise control' &mdash; you can set a destination and then accelerate time and simply watch as your characters journey).
But nevertheless, in The Witcher 3, a decision was made to pack incident fairly densely &mdash; because players would find just travelling boring. This leads to a situation where peaceful villages exist two minutes travel from dangerous monsters or bandit camps, and the suspension of disbelief gets a little strained. Building a world big enough that a market simulation is believable means that for the individual, the travel time to a market where a particular desired good is likely to be cheaper becomes costly in itself. Otherwise, there's no arbitrage between markets and no ecological niche for a merchant to fill. The journey time from market to market has to be several in-game days.
An in-game day doesn't have to be as long as a wall clock day, and, indeed, typically isn't. But nevertheless, doing several game days of incident-free travel, even in beautiful scenery, is not going to be engaging &mdash; which implies a fast-travel mechanic.
@ -66,3 +64,5 @@ So I'm thinking of a different mechanism: one I'm calling cruise control.
You set out on a task which will take a long time &mdash; such as a journey, but also such as any routine task. You're shown either a 'fast forward' of your character carrying out this task, or a series of cinematic 'shots along the way'. This depends, of course, on there being continuous renderable landscape between your departure and your destination, but there will be. This fast-forward proceeds at a substantially higher time gearing than normal game time &mdash; ten times as fast perhaps; we need it to, because as well as doing backgound scenery loading to move from one location to another, we're also simulating lots of non-player agents' actions in parts of the world where the player currently isn't. So a 'jump cut' from one location to another isn't going to work anyway.
The player can interrupt 'fast forward' at any time. But also, the game itself may bring you out of fast forward when it anticipates that there may be action which requires decision &mdash; for example, when there are outlaws in the vicinity. And it will do this **before** the player's party is under immediate attack &mdash; the player will have time to take stock of the situation and prepare appropriately. Finally, this will take place in the full open world; the player will have the option to choose *not* to enter the narrow defile, for example, to ask local people (if there are any) for any news of outlaw activity, or, if they are available, to send forward scouts.
(It's worth noting that [Kenshi](https://lofigames.com/), a game I'm coming to greatly admire, does not allow fast travel at all, but has an equivalent of 'cruise control' &mdash; you can set a destination and then accelerate time and simply watch as your characters journey).

View file

@ -36,7 +36,7 @@
The objective of this essay is to outline an algorithm for creating inhabited landscapes in which games can be set, which are satisfyingly believable when rendered in three dimensions. The objective of creating landscapes 'procedurally' that is, with algorithms is that they can be very much larger than designed landscapes for the same richness of local detail. This does not mean that every aspect of the final landscape must be 'procedural'. It would be possible to use the techniques outlined here to create landscapes which were different every time the game was played, but it would be equally possible to create a landscape which was frozen at a particular point and then hand edited to add features useful to the game's plot. And while I'm principally thinking in this about role playing games, this sort of landscape would be applicable to many other sorts of games strategy games, god games, first person shooters...
### The physical geography
### Physical geography
Consider our landscape as, once again, a fractally folded sheet on which any given point has characteristics based on its elevation and orientation. There are two critical levels water level and treeline. The water level is, overall, sea level, but in the case of a localised depression it is equal to the lowest land height between the depression and the sea (lakes form in depressions). Computing the fractal sheet forms stage one in computing the landscape. Next, we need functions which, for any given point on the landscape, compute two different dimensions of soil fertility: water and warmth. We'll assume a coriolis prevailing wind blowing from the west, bringing in damp air from an ocean in that direction. Western slopes are wetter than eastern slopes. In principle, also, there's likely to be a rain shadow to the east of high ground leading to considerable aridity, but that may be too expensive to compute. Rain runs swiftly off steeper slopes, more slowly on flatter ground, so flatter ground is wetter than steeper ground. Water flows down hill, so lower ground is on the whole wetter than higher ground. This isn't a precise model of soil hydrology, but I think it's good enough. From each lake a watercourse follows the lowest possible path to the sea. Watercourses modify the land overwhich they flow, carving out a route at least sufficient to carry the amount of water collected in the watershed above each point. Where watercourses flow down steeper gradients, they carve out gullies, possibly with waterfalls. Where they cross shallower gradients or level ground, they become broader. Computing the watercourses becomes the second stage of computing the lanscape.

33
doc/Simulated-genetics.md Normal file
View file

@ -0,0 +1,33 @@
# Simulated Genetics
If we're going to have a world with a multi-generational population of hundreds of thousands of procedurally generated characters, and we're to persuasively represent each character as being related to others, then we have to have a mechanism for making children look reasonably like their parents, to have family resemblances among cousins, and so on. We need to do this at reasonably low data storage and algorithmic cost, firstly because we have to store all these characters, and secondly because (especially when the player approaches an urban centre), we may need to instantiate models for a lot of them in limited time.
This note discusses how this might be done.
## The pseudo-genome
Suppose we have a binary vector of memory, such that when a 'child' was born to two parents, bits were taken at random from the parents' chromosomes to populate the child's genome -- which is sort of, very roughly, what happens in actual biology -- how big would that genome have to be? After all, the full data size of the human genetic code is enormous. But actually, we don't need to simulate anything like so large. After all, all our genome needs to encode is morphology, and only sufficiently to enable the player to recognise and distinguish characters.
My hunch is that a 32 bit genome is sufficient, if we code it carefully. It allows for four billion distinct appearances to be encoded, which is way more than we need. So here's how such a genome might be structured:
| Field | Bits | Interpretation |
| -------------------- | ---- | ------------------------------------------------------------ |
| Ethnic type | 4 | Ethnic type. Most significant bits both indicate dark skin, with [??11] indicating dark skin/curly hair and [??01] indicating dark skin/straight hair |
| Skin tone | 3 | Plus second-most significant bit from ethnic type (i.e. [??1?]) as most significant bit. This means sixteen distinct tones, with the darkest tone of 'pale skinned' ethnicities just very slightly lighter than the palest tone of 'dark skinned' ethnicities. |
| Freckles? | 2 | [11] means freckles, any other value means no freckles. Freckles won't be visible on very dark skin. |
| Hair colour | 3 | Plus second-most significant bit from ethnic type (i.e. [??1?]) as most significant bit. Least significant bit does not contribute to tone but indicates red tint. Thus eight distinct degrees of darkness from pale blond to black, plus red tint which can affect any degree of darkness. |
| Eye colour | 2 | Plus second-most significant bit from ethnic type (i.e. [??1?]) as most significant bit. Thus eight values: [000] blue; [001] hazel; [010]...[111] shades of brown lighter->darker. |
| Height | 3 | Height when adult; children will have a scaled proportion of their adult height, and the same height value in the genome will result in female body models 95% the height of an equivalent male body model. So [000] codes for 150mm, [111] codes for 200mm, with eight distinct values |
| Gracility/Robustness | 3 | Slenderness to stockiness of skeleton/armature build, with [000] being very slender and [111] being very broad/heavy. |
| Age-related change | 3 | People get white haired at different ages; some men go bald and some do not. The sons of the daughter of a bald man should have a chance of inheriting age-related baldness, although their mother won't express that gene. So I'm allowing here for eight different profiles for age related change, although I'm not yet clear what the exact values would mean. |
That's twenty-two of our thirty-two bits, leaving 10 bits (1024 values) for face models; but actually, that 2048 distinct possible face models, because the morphology of female faces is different from the morphology of male faces. Although, again, we might encode gender into the genome, which would mean only bits left for face models, but still, 1024 distinct faces is plenty, especially as each face model would need to have its own aging model, so that characters would credibly age.
## What's not included in the genome
Things which are cultural are not included in the genome; things which are lifestyle related are not included in the genome. So, for example, gracility/robustness, is not the same as skinniness/fatness, which are mostly lifestyle/diet related rather than genetic. There are some occupations (e.g., blacksmith) where you'd be unlikely to be fat (but might be very robust). Also, the same character might grow fatter (or thinner) over time.
Similarly, hairstyle and beard-wearing are cultural (and occupational) rather than genetic, and closely related to choice of clothing. So while we do need to represent these things, they're not things which should be represented in the genome.
Injury-related change -- which would especially affect soldiers and outlaws especially but could affect any character -- also needs to be encoded somehow (and may cause real problems), but this is also not a problem for the genome.

View file

@ -0,0 +1,76 @@
# Towards a procedural animation API
I've been watching this animation tutorial, and I'm impressed with its simplicity. This seems to be to be something it would be possible to do, and it started me thinking about what I wanted from a procedural animation API.
<iframe width="800" height="504" src="https://www.youtube.com/embed/LNidsMesxSE?si=QgaN2aHG0g71aWkX" title="An Indie Approach to Procedural Animation" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
The game is now open source, with the source available [here](https://github.com/WolfireGames/overgrowth/). It's available on [Steam, here](https://store.steampowered.com/app/25000/Overgrowth/).
So: what have we here?
A simple character rig with a small number of key frames which can adaptively negotiate a moderately complex terrain. Inverse kinematics is used, but the core of the animation is key-frame animation with well thought out interpolation, and it all looks remarkably persuasive. This looks buildable.
So: what do I actually need?
## Smooth continuous movement on complex terrain
Characters need to transition from one movement to another movement smoothly, without sudden jums or jerks. Turning needs to look physically plausible.
## Animation for several skeleton types
Creatures I need to animate include
1. People: upright bipedal motion;
2. Horses: even-length-legged quadripedal motion;
3. Camels: also even length legged quadripeds, but their gait is different from horses, although the skeleton might be similar. So: different key frames? Or something more elaborate than that?
4. Seals: primarily aquatic quadrupeds, with forelimbs considerably longer than back limbs, and all limbs much shorter than the other quadripeds under consideration. But I'm not sure how much I need to actually animate them.
5. Dragons: exist in the world, but aren't necessarily going to appear in version one of the game. A much more complicated problem.
6. Birds: but don't need to animate them close up or landed. However, not all birds fly using the same 'gait', so, again this may be complex.
7. Other quadrupeds, such as dogs and cats; but these are a long way down the priority scale.
At the proof of concept stage, I only need animated people; and the only reason for cataloguing the other things I need to animate is that the animation framework needs to be able to handle multiple skeleton types.
It's also worth pointing out that in Cyberpunk 2077, it's very noticable that several different gaits are implemented for people: there is a noticably distinct 'fat person' gait, and several different gaits that are used, for example one extremely sexualised female gait, used mainly for characters who are sex workers, but for a small number of other female characters. The point here is that not all characters walk the same, and having distinctive gaits for some characters or classes of characters decidedly adds to a game's persuasiveness.
## The API
### (move-to model terrain target)
Plans a route across the terrain from where the model is to the target (which can be either a location or an object, including another potentially moving character), avoiding obstacles and choosing the easiest path across slopes, and produces a route; animates the model along that route, using the keyframe-based system described in the video, with inverse kinematics to ensure feet touch the ground.
### (look-at model terrain target)
Turns the model's gaze, and, if necessary, head and body, to face towards the target.
### (sit-on model terrain target)
Causes the model to sit on the target, moving to it first if necessary. If the target is approximately chair-height, sit on it as if on a chair; if it's a horse or camel, sit on it as though to ride; otherwise, sit cross legged. If the target is just a location, sit cross legged on the terrain surface at that location.
Obviously, what I've described there is partially specific to upright bipedal models; horses and camels don't sit on chairs!
### (lie-on model terrain target)
As above, but lie down.
### (drink-from model terrain target)
As above, but drink. Target is expected to be a drinkable container, such as a mug, flask or bottle, or else a point in the terrain which is flooded.
### (eat-from model terrain target)
### (strike model terrain target implement vector)
### (thrust model terrain target implement vector)
Two closely related animation calls, both of which might be used both in combat animation and in craft activity animation. **BUT** both combat animation and craft activity animation are much more complex problems which this not does not address.
## Other things which need to be animated
### Conversation
In conversation, people move to a convenient distance from one another, typically face one another, typically take turns to say things, frequently use hand gestures when speaking. The intensity of gestures will vary with the emotion being expressed. The animation of NPC-to-NPC conversation is if possible more complex to get right than of player character to NPC.
### Combat animation
### Craft activity animation
Both of these will be very complicated to get right.

View file

@ -0,0 +1,78 @@
# Tree library evaluation
This is a comparative evaluation of open source tree libraries that I have found that I could make use of. It's entirely personal and subjective!
## [SimArboreal](https://github.com/Simsilica/SimArboreal)
### Overview
Library by Paul Speed, who's a senior and prolific developer in the jMonkeyEngine community; designed to work with jMonkeyEngine, and consequently integrates well with it.
### Licence
[BSD-style licence](https://github.com/Simsilica/SimArboreal/blob/master/src/main/resources/license.txt).
### Assessment
Produces trees which are quite realistic but only for a limited range of broad-leaved species. The trees do have modelled roots, which is relatively unusual. The trees sway in virtual winds, although to my eye trunks sway too much and thinner twigs too little. A limited number of textures are supplied, but new textures can easily be added so this isn't an issue. Handles Level of Detail automatically within the context of the jME3 libraries, which is a real bonus.
Does not provide the range of species, or of stages of growth, I want. To add convincing coniferous trees, or trees with more than one primary branching point on the main trunk, would require extra coding. The way leaves are handled is crude, but looks surprisingly persuasive. The codebase is reasonably well written and understandable, but there is virtually no documentation. If I have to build on someone else's library, this wouldn't be a bad choice. The one to beat.
## [Tree3D](https://github.com/SnailBones/Tree3D)
### Overview
Looks like a student project, or something done fairly quickly as an exercise.
### Licence
None specified, not even 'public domain'. So might be a bit sketchy to copy from.
### Assessment
This is definitely not as complete or ready to use as SimArboreal; although it does build, the user interface doesn't work with modern Java. Whether it ever worked I don't know, but I wouldn't be confident. Code is reasonably well written, but almost completely undocumented. There is no rendering of bark or of leaves; although the branching structure is excellent and the variety of morphologies available is good, boughs do not bend.
However, algorithmically, this has a much better understanding of how trees grow, and of tree morphology, than SimArboreal. A hybrid taking growth algorithms from this and texture, wind, level of detail and jME3 integration from SimArboreal might be relatively to do.
## [Proctree.js](https://gltf-trees.donmccurdy.com/)
Very polished demo project by Paul Brunt, author of a key JavaScript WebGL 3D library; but in JavaScript, so not directly usable.
### Licence
None specified, not even 'public domain'. So might be a bit sketchy to copy from.
### Assessment
Very beautiful, algorithmically elegant, excellent variety of morphology. But
1. No textures;
2. No wind sway;
3. No roots;
4. No level of detail handler;
5. No leaves;
6. No modelling of bough curvature;
7. Wrong language;
8. Relatively poorly structured code;
8. No documentation.
This would be great to steal inspiration from for a new library of my own, and could possibly be used to inspire a significant extension to SimArboreal, but in its current state it isn't usable.
## What none of the candidates offer
None of the candidates have
1. Seasonal change;
2. Species prototypes;
3. Broken boughs;
4. Leaning or nonstraight primary trunks;
These are all features I want. The same cherry tree encountered in spring should be bedecked with blossom; in summer, green leaved; in autumn, red leaved and heavy with berries; in winter, bare. As seasons change as the player explores the game world, the trees need to change with them.
Cherries need to have green leaves tapering to a point at both ends, pink flowers in late spring, large red berries (and flocks of birds) in autumn. They need to have moderately tall trunks with upward pointing, quite stiff boughs. Pines need to have the same dark green needles all the way through the year, and, typically, tall straight trunks with a few irregular coronets of living branches near the top and occasional dead and probcably broken boughs lower down. And so on. I need the same procedural code to be able to generate thousands to millions of recognisably distinct individual trees of a biome-appropriate variety of recognisable species across the map.
They need to be individual and distinct at least partly because users are likely to recognise some of them as landmarks. And they need to be reproducably generatable from mininal seeds, because there's no way you can store that many models at anything like the level of detail I need.
## Conclusion
At this point it's a choice between rolling my own, or using Paul Speed's SimArboreal and enhancing it (hopefully with his approval and co-operation). In the short term, if I finalise the engine decision on jME3 (and I think I'm fairly close to doing that), SimArboreal will do as a placeholder. However, I will continue to look for other possibilities, because I have so many other things to build, and although I do want good quality forests I don't have that much time to invest in them just now.

74
doc/Worlds-and-flats.md Normal file
View file

@ -0,0 +1,74 @@
# Worlds and flats [obsolete]
*This essay is from 2008, and is now at least partly obsolete; but there's useful stuff in it which is worth holding onto.*
## Of Compartmented Worlds
Playing The Witcher has got me thinking again about an algorithm for rendering a world which I first thought of twenty-five years ago. Then, it was a hack for dealing with the fact that the computers of the day didn't have much memory or horsepower. Now, it's a hack for dealing with the fact that &mdash; when considered against the complexity of a world &mdash; the computers of today still don't have enough memory and horsepower. Mind you, today I'm contemplating photorealistic scenes, whereas then simple line and wash would have been good enough, but...
The algorithm for rendering I'll call 'flats'. But before we get to discussing flats, lets discuss worlds.
The world of The Witcher (and other games based on the Aurora engine) is composed of areas. One area is loaded into memory at a time; when the player reaches an area boundary, the area is unloaded in toto, and the next area loaded, also in toto. The result is a noticeable interruption in game play. There's also, normally, a noticeable visual disjunction at the boundary; the new area uses a different 'tileset', which is to say, set of bits of scenery. When you look across a boundary, the scenery often appears different from what you find when you cross the boundary and arrive at the other side.
Finally, you can only cross boundaries at specific gateway points. For example, Chapter Four of The Witcher takes place in a continuous rural space composed of three main areas: the lakeside, the village, and the fields. Between the lakeside and the other two regions there's a wooded escarpment, which provides some logical justification for the fact that there are actually only two places you can actually cross it &mdash; from the lake shore, either up the road to the village or else through a series of glades to the fields. But between the village and the fields there's no such logic. There are a pair of gateposts, and you must cross between those gateposts &mdash; but the landscape appears continuous, with no visible barrier. It's an artifact of the game engine.
So, how to deal with this?
My interest, let's be frank, is in story telling; and the nature of story telling is moderately constrained plots. In computer mediated story telling the reader/player can and should be able to explore the plot in his own way, make his own choices, take his own path through the environment, encounter the elements of the plot as he encounters them on that path, and it's the job of the story teller to make that engaging whatever path the reader takes. But if the reader chooses to ignore your hints and wander out of the area you've populated with plot altogether, there's two things you can do. One is put up physical barriers which stop him (although the silly field fences in Chapter One of The Witcher do *not* count, as it's obvious that Geralt could simply hurdle them; they are just another artifact).
## Of Finite and Infinite Worlds
But an infinite world is not required for the sort of stories I'm interested in; the sort of stories I'm interested in take place in, at best, regions of infinite worlds. Just because I don't choose to use all of it, of course, is not a reason that a world should not be very large.
There are plenty of fractal mathematical equations which map an infinite three dimensional surface with landscape like features. If such an equation gives you land heights, then altitude, steepness and orientation will give you soil type and vegetation cover. There is no need to store a whole world in order to be able to reproduce it exactly when the player follows the same route through it for a second time; it is sufficient to start with the same seed. So a world need not take up vast amounts of disk space for pre-mapped scenery; scenery need only be mapped as it comes in sight. This is fundamentally the trick used by Elite to pack a large, reproducible universe into less than 32K of RAM, and it still works today.
### Of River Systems
However, there are reasons to prefer that a world be pre-mapped, at least at coarse grain. One example of why is river systems. It's trivial that we render a river at the bottom of a valley, but it isn't trivial to compute how wide and deep that river should be. To calculate that we have to explore the extent of the watershed upstream of any given point, and sum the rainfall on it, which in turn is a factor of exposure to prevailing airflow and the proximity of ocean to windward. It's computable, but it's much more efficient to compute it once and cache the results, especially since for any given river system it's a recursive function.
Furthermore, rivers cause erosion, changing the landscape through which they pass, cutting gorges on steep slopes (especially if soft), building up flood-plains in flatter areas downstream. Some fractals are naturally extremely landscape-like, but it seems to me &mdash; better mathematicians might prove me wrong &mdash; to realistically render river systems requires some degree of post processing, and post processing which would be expensive to do repeatedly in realtime.
### Of Human Settlement
Human settlement is a separate issue. Many years ago I wrote a program which modelled the spread of human settlement over a landscape.
Human settlement is not random. Human settlement follows rules and patterns. Pioneers settle in places which have a sufficient spread of resources to meet their year round needs; they settle near to easy routes from their parent settlement. Pastoralists need grazing land and water; they spread up river systems, but avoid marshy areas. They settle where there is open grazing, but often close to a forest edge for access to timber. Second wave settlers prefer to settle close to existing settlers, for mutual protection and help. Cereal growers join these settlements where the depth of soil is optimal for crops. As the settlement grows and pressure on land increases, the forest edge is cut back both for building material and to increase the available agricultural land. If a settlement fails, the forest may reclaim this land
Road networks develop. People travel between settlements by the easiest route &mdash; but the very fact a route is travelled makes it easier. A path gets cleared; later, people fill in boggy bits and bridge streams, to make their own passage easier or to encourage trade through their lands. Because as a road grows more important, so the settlements along it grow more important, and as the settlements along it grow more important so the roads between them grow more important. The road network, then, is a dynamic fractal which interacts with another dynamic fractal, the distribution of human settlement.
The program I wrote was a cellular automaton which modelled human settlement in only thirty states. It did a remarkably good job. Settlement would spread across a landscape; settlements in strategically beneficial areas would grow faster, develop temples and markets sooner, and thus become important foci of the roads system; other settlements would wax and wane, some falling into ruin; new waves of settlers might settle in slightly different areas.
More states would be better, give a richer, more subtle model, But this demonstrates that it's easy to design a program which will settle a landscape in a realistic way automatically. Once again, though I think it can be done more realistically if it is precomputed and cached rather than if it is generated from the landscape fractal.
In summary: yes, I think it's possible to have a near-infinite world which is satisfying and can be reproduced at will from a seed, but the stories I want to tell do not call for infinite worlds and if the world is finite I believe it can be made still more satisfyingly realistic by pre-computing and caching things like river systems, afforestation and settlement patterns. Either way, though, the world can be very large &mdash; much larger than the worlds of current near-photo-realistic games. The world of The Witcher, for example, is a few hundred hectares; I'm envisaging storing hundreds or thousands of square kilometres in similar data size and with a similar expenditure of artist's effort.
## Rendering, and the Flats idea
Rendering a convincing distant view in computer-generated virtual environment is hard. There's an enormous amount of data in a distant view, and if the viewer is moving in real time it becomes computationally unaffordable, even on machines with a great deal of horsepower. Games typically work around this problem by either angling the camera downwards, or else rendering a high degree of atmospheric haze &mdash; it's always slightly foggy &mdash; so there is never a distant horizon.
Movies shot in studios often have wonderful, detailed backgrounds to their sets. Vistas of far mountains and great cities... of course, the far mountains and great cities don't exist in the set. They're painted on large canvases called 'flats'. The flats illusion depends on the camera not moving too much, because of parallax &mdash; nearer things should appear to move relative to further things, and on a flat they don't.
But. But.
For a player moving in a computer game the field of view is quite restricted &mdash; it's no more than thirty degrees, typically straight ahead as he moves. Parallax movements are less significant straight ahead. A single flat still isn't going to work, but in many animated films a system of multiple flats is used, with the nearer flat moved relative to the further flat to give an illusion of parallax. This can work very well.
Suppose one projects onto the world a hexagonal grid &mdash; it doesn't have to be hexagonal, but I think that is likely to work best &mdash; with a cell size of about 100 metres (the exact cell size depends a bit on the speed of movement of the player, for reasons which will become apparent). Cells are grouped into metacells of seven cells (if square, then metacells of nine cells). For each cell, there are six inner flats. Each inner flat consists of a rendering from the centre of the cell of everything more than one cell distant, but less than five cells distant, over a 60 degree arc of view.
For a given area of the world the distant view doesn't change very much. We don't, therefore, have to compute a set of outer flats for every cell, just for every metacell. The outer flats each consist of a rendering of the scenery more than one whole metacell away, from the centre of the metacell.
To render a scene, then, we first paint the outer flat for the metacell the player is in, in the direction the player is looking. Over that we paint the inner flat for the cell the player is in. Over that we render the actual objects in the adjacent cells which fall within the viewing area. Over that we render the objects in the current cell. Thus we only have to render in real time certainly no more objects than can already be rendered by systems which clip for distance either by angling the camera down or by using fog, and yet still manage a realistic distant view.
## Rendering the Flats
OK, so when do the flats get rendered? After all, if you're going to pre-render six full colour full screen resolution flats for every hundred metre cell in the world, then either your data volume is going to get enormous or your world is going to get pretty constrained &mdash; which was just what we were trying to get away from. And if you're going to multiply that with flats rendered for every time of day and every weather condition &mdash; well, it's not feasible.
You cannot realistically pre-render the flats, in my opinion. Or if you can, you're going to have to give them so much real time post processing that you will lose the benefit. Pre-rendering the flats is not the idea. But if they are rendered in real time, where is the benefit...?
There's a middle way. Running straight forward at top speed a player crosses a hundred metre cell in about a minute, during which to give an illusion of continuous movement at least nine hundred full screen frames must have rendered. But the flats don't change in a minute. The flats don't change in five minutes. They don't need to. Even if rain clouds are sweeping across the landscape, it's OK for the distant view still to be sunny five minutes after the rain reaches you, or vice versa. If you can render a high proportion of the detail in a view only once every nine hundred frames, you've saved a lot of processing.
So there is a continuous background process running which renders flats. It does it all the time. It prioritises making sure that a flat exists for every direction the player may look in in the next minute &mdash; that is, every direction from the cells and metacells he's currently heading towards. Having done that, it renders flats for cells to either side which he might turn to. It maintains in memory a small stock of flats from recently visited cells, so that if the player turns back they don't have to be repainted in a hurry; and if a flat is more than about five minutes &mdash; 4,500 frames &mdash; old, it may repaint it to update time-of-day lighting or weather effects.
Obviously, quite a lot of the time the join between two adjacent flats will be in view. I don't see this as a problem. Just naturally, the rendering of the flats should essentially form segments of a hoop, so the join between two adjacent flats should not be perceptible.
## Artifacts
Inevitably, there will be undesired artifacts of this system. Significantly, mobile objects &mdash; 'non-player characters', the avatars of other players, monsters and computer mediated creatures in the landscape &mdash; more than two cells away will not be visible. The flat is static, so it can't have moving characters on it. There may be some algorithmic way round this, since one hundred and fifty metres away is rather close for people to suddenly vanish; but it is not a problem I have a solution for.
Again, if the player is looking sideways as they cross a metacell boundary, there will be a jarring sudden shift in parallax. I acknowledge that and think it just can't be helped; that the benefits in terms of quality of view for given computer power, will render it acceptable.

View file

@ -167,6 +167,7 @@ different top level goals. The following are some plausible top level goals:
4. **Climber**: To climb as high as possible in the social hierarchy, to become Tyrranos or Imperator;
5. **Conqueror**: To build the largest possible realm under your control;
6. **Citizen**: To build a secure and comfortable home, able to feed and protect those within it;
7. **Hoarder**: To accumulate the greatest possible amount of wealth.
In this typology, a hero is a master soldier, and a sage a master scholar.
Each of these types should be capable of being 'scored' by a real function

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show more