Added the world generator addons from Broken Seals.

This commit is contained in:
Relintai 2023-10-08 14:46:30 +02:00
commit c3244e21b9
43 changed files with 4365 additions and 0 deletions

27
.gitignore vendored Normal file
View File

@ -0,0 +1,27 @@
*.d
*.o
*.meta
.import
.sconsign.dblite
.DS_Store
export/**
release/**
.vs/*
.kdev4/*
.vscode/*
TestRWTextures
_build/*
_binaries/*
game/android/build/*
*.blend1
.dir-locals.el
build.config
__pycache__/*

19
LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2019-Present Péter Magyar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

394
README.md Normal file
View File

@ -0,0 +1,394 @@
# Broken Seals
A 3D third person RPG. With both multiplayer, and singleplayer capabilities.
The main gameplay-loop goal is to create an experience with enough complexity and depth, that can rival the more old-school MMO- and action rpgs, because nowadays I feel like that is something that got lost.
I want the game to run on every platform, but the game design is PC first. From the testing I've done this is not going to be an issue.
This project now uses the ![Pandemonium Engine](https://github.com/Relintai/pandemonium_engine), which is my custom version of godot.
The project also requires the presence of some of my engine modules, Pandemonium contains all of them. See [here](https://github.com/Relintai/pandemonium_engine/tree/master/modules).
You can get binaries under the releases tab [here](https://github.com/Relintai/broken_seals/releases).\
You can also try a live version running in the browser [here](https://relintai.github.io/broken_seals/).
Unfortunately the web editor needs custom http headers to work and I can't set that up from github.io, so right now I don't have a hosted version of that.
#### On Desktop
![Broken Seals desktop](pictures/screenshot_desktop.jpg)
#### On Touchscreens
![Broken Seals on touchscreen](pictures/screenshot_touchscreen.jpg)
## Status
Currently I'm working content.
Roadmap:
- Have a few animal models that can be used for the starter zones.
- Have a few building models.
- Add in sounds.
- Have some ambient sounds as music.
- Set up a proper starter zone.
- Implement the naturalist's spells.
- Add a male model.
- Add more classes.
- Then start working on new zones.
Some planned changes that will come sometime:
- Add support for multiple worlds. (Just have to make use of the new World class in the engine. The scene tree (Entities and Entity Bodies) will need small changes.)
- Fix up multiplayer, and implement missing things (like animations for clients).
## Features
### Multiplayer
Multiplayer was broken for quite a while, so currently it has a lot more bugs than it used to.
Most of these should be relativelty easy to fix.
- Authoritative server implementation. (Except for movement. Can be done though, I'll do it eventually, but it's usual for these kind of games to not have authoritative movement.)
- You can create, and join to servers.
- Movement works. Although the animations are not yet implemented for client players.
- Targeting works.
- Spell casting works. Although auras have some issues for now.
- Inventory management should work.
- Stuff like vendors, trainers should all work. I think except for crafting (I think just some methods need to be marked as RPCs, and they might need to need to call eachother via rpcs).
### Characters
- Main and secondary stats all work, they are also customizable in the project settings. They also have built in maint stat -> secondary stat conversion support.
- Character resources all work and scriptable. (Like health, mana, speed, energy etc) Also you can dynamically add it and remove it from a character.
- Tab targeting support.
- Spells, and auras are fully scriptable, and networked.
- Actionbar, actionbar profiles support.
- Spell learning support.
- Talent support, with multiple talent trees.
- Loot.
- Equipment support including weapons, clothes, and also other attachments. Although starter gear support is not yet finished.
- Support for changing clothes via texture merging.
- Support for changing parts of models via clothes. Also support for alternative bodyparts.
- Character models are using merged meshes and textures, with generated LOD. (This is also multi threaded, with fallback when no threads are available.) This system is using MeshDataResources.
- Generic attach point support for the character skeletons. (Spell cast particle effects, spell effects, also the same system can be used for weapons.)
- Interaction support.
- Vendors, Trainers, Crafting.
- Fully scriptable ai support.
- Control over characters can be easily changed by the server, and the character bodies are scripted to act accordingly automatically. For example mind control effects can be implemented with this system.
Missing:
- Character customization support (like selecting hairtyles). It's mostly there, but some crucial features are still missing.
- Temporary character model change support. Think of polymorph effects, toys etc. Needs the character customization support first.
### Terrain
- Multi threaded chunk generation. It will even work when no threads are available, also in this case the work gets distributed over multiple frames (although one of the steps is a bit too long, so it still needs some tweaks).
- Prop system. You can serialize scenes into a more efficient format than scene files. These can contain lights, meshes, rooms and portals, etc. The system is scriptable. Scene hierarchies also work.
- PropInstance node, which can mesh and put props into the scene.
- Per chunk material support, even for props.
- Terraman: prop support, even with mesh (and texture) merging. If you look at the trees on the screenshot, they are merged together per chunk, and they all share the material, and shader. Also if you serialize lights into props, they are added as vertex lights.
- Terraman and PropInstance: Vertex light support. You can add vertex lights (via code, or the prop system), and the meshes will be colored with it.
- Terraman: Vertex colors are also used to achieve the main style. (RAO).
- Terraman: Vertex color based ambient occlusion support.
- Terraman and PropInstance: LOD support, even for prop meshes.
- Terraman and PropInstance: LOD generation is scriptable.
- Dungeon generation support via a separate prop based system. Dungeons are generated below ground, with teleporters to them. Also support for turning off the terrain engine while the player is inside a dungeon.
- Procedural world generation. [See here](#terrain-generation).
### UI
- Menu and game ui.
- Actionbars with keybind support. Also the icons that you drag to the actionbar actually gets merged into the ui's texture to reduce drawcalls.
- Character, talent, spellbook, crafting, inventory, loot, vendor, trainer windows are all implemented.
- Easily scriptable options dialog.
- The menu has full support for keyboard / controller navigation. (The game itself misses it at the moment though.)
- Touchscreen controls. It will also make the buttons bigger if it detects a touchscreen.
- Keybind window.
- About window.
## Project overview
As stated in the opening section the project uses a custom version of the godot engine.
The project's workflow has been set up so you can easily compile this version for yourself if you want to.
See the [Compiling](#compiling) section if you want to know how to do this.
### Engine
Currently the [Pandemonium Engine](https://github.com/Relintai/pandemonium_engine) is used as the engine for this project,
which is a heavily customized verison of the [Godot game engine](https://godotengine.org/). It's based on the 3.x branch.
It contains my engine modules, and also it got significanlty slimmed down compared to vanilla Godot.
For a more in-depth changelog see it's changelog file [here](https://github.com/Relintai/pandemonium_engine/blob/master/CHANGELOG.md).
### Game
The [/game](https://github.com/Relintai/broken_seals/tree/master/game) folder contains the game's code and assets.
This is the folder you are supposed to open in the editor.
The game's folder structure should be (hopefully) mostly self explanatory.
#### Game Modules
I designed the game's code to be highly modular, so I created a [loader module](https://github.com/Relintai/broken_seals/tree/master/game/scripts/game_modules). \
It will look for files named ` game_module.tres ` and call methods on them on certain events.\
This system uses the [DataManager](https://github.com/Relintai/broken_seals/blob/master/game/scripts/game_modules/DataManager.gd) singleton.
For example this is how the ui initializes itself:
The player's [body](https://github.com/Relintai/broken_seals/blob/master/game/player/Body.gd) script requests the ui nodes from the [DataManager](https://github.com/Relintai/broken_seals/blob/master/game/scripts/game_modules/DataManager.gd) singleton (like ` var ui = DataManager.request_instance(DataManager.PLAYER_UI_INSTANCE) `). And then the data manager will instance it's ` player_ui ` scene, and call all module's ` on_request_instance ` methods, while also passing the newly instanced scene to them.
These module scripts are also responsible for collecting all spells and then setting them into the ESS singleton, so they are actually castable.
This is the [module](https://github.com/Relintai/broken_seals/blob/master/game/modules/entity_classes/naturalist/game_module.tres) for the naturalist, and it's [ResourceDB](https://github.com/Relintai/broken_seals/blob/master/game/modules/entity_classes/naturalist/resource_db.tres), which will be merged into a central resource db for ESS.
Note that the module resources are sorted by their resource paths, so spells should always get the same id, on every platform every time.
This is to optimize networkd spell casts.
Most of the game assets ended up under the modules folder [here](https://github.com/Relintai/broken_seals/tree/master/game/modules) for this reason,
however these might get moved, if I find a better arrangement.
#### Terrain generation
The terrain generation is now handled by the new [world_generator](https://github.com/Relintai/broken_seals/tree/master/game/addons/world_generator)
addon.
Right now the terrain is only going to be pseudo-random, as generating proper connected worlds are kind of super difficult,
especially if you also have to mesh them in 3d. \
I think this solution can be extended later to be able to do a full continent / world randomization / generation.
For now the idea is that we have a World resource, this contains Continents, those zontain Zones, and those contain SubZones.
The position and size is predetermined by the designer. And then when a chunk needs to be generated it gets put into this world, and then these generate it's data.
- World does mostly nothing on it's own for now, except for holding continents.
- Continents handle things like oceans, and big mountains.
- Zones generate proper terrain, and add props. They need to blend into continents.
- SubZones can be used as spawners, prop spawners, or they can even do terrain modifications.
So when a chunk needs to be generated, first the world gets it, then all continents which intersect with it's position,
then all zones which intersect with it's position, then all subzones which intersect with it's position.
The editor contains an addon to help with editing the world.
## Editing the game
Grab the engine itself, and then open the project inside the `game` folder.
After the initial import it might need an editor restart, however everything should work after that.
If you want to use master, you will likely need to build the editor for it if the c++ side had breaking changes since the last release.
## Compiling
First make sure, that you have everything installed to be able to compile the engine.
See the [official docs for compiling Godot](https://docs.godotengine.org/en/3.4/development/compiling/index.html) for more info.
My setup/compile script uses the same tools, so you don't need to install anything else.
Even though the project doesn't use godot anymore, their docs are still sufficient.
Now let's clone this repository:
``` git clone https://github.com/Relintai/broken_seals ```
cd into the new folder:
``` cd broken_seals ```
Now let's run the project's setup script, by calling scons without arguments.
``` scons ```
This will clone and setup the engine, and all of the required modules into a new `engine` folder inside the project, using http.
(If you want to use the github's ssh links append `repository_type=ssh` like ``` scons repository_type=ssh ```)
Once it is done you can compile the engine.
To build the editor on windows with 4 threads run the following command:
``` scons bew -j4 ```
To build the editor on linux with 4 threads run the following command:
``` scons bel -j4 ```
I call this feature of the setup script build words. [See](#build-words).
Once the build finishes you can find the editor executable inside the `./engine/bin/` folder.
For convenience there is a provided `editor.sh`, or `editor.bat` for running it from the project's folder.
These will create a copy, so you can even compile while the editor is running.
Alternatively if you don't want to use build words, you can also just go into the engine folder:
``` cd engine ```
And compile godot as per the [official docs](https://docs.godotengine.org/en/latest/development/compiling/index.html).
### Build words
The project's setup script contains support for "build words". These can be used from the root of this project.
For example to build the editor for windows with 4 threads you can use:
``` scons bew -j4 ```
The first argument must start with b (build), then it needs to be followed by a few abbreviations (the order does not matters)
The rest of the arguments will be passed directly to godot's scons script.
#### Editor
Append `e` to build with `tools=yes` a.k.a. the editor.
``` scons bew -j4 ```
if you omit `e`, the system will build the export template for you. For example:
``` scons bw -j4 ```
This will be the `release_debug` windows export template.
#### Platform abbreviations
`l`: linux \
`w`: windows \
`a`: android \
`j`: Javascript \
`i`: iphone (Not yet finished, use `build_ios.sh`, and `build_ios_release.sh`) \
Mac OSX: Not yet finished, use `build_osx.sh`
#### Target abbreviations
By default the system builds in release_debug.
Append `d` for debug, or `r` for release.
``` scons bewd -j4 ```
build editor windows debug
``` scons bwr -j4 ```
build windows release (this will build the windows release export template)
#### Shared modules
Note: This only works on linux!
append `s` to the build string.
Optionally you can also make the build system only build a target module, by appending one of these:
`E`: Entity Spell System \
`T`: Texture Packer \
`V`: Voxelman \
`W`: World Generator \
`P`: Procedural Animations
Example:
``` scons belsE -j4 ```
build editor linux shared (Entity Spell System) with 4 threads
Note: to easily run the editor you can use the `editor.sh` or `editor.bat` in the root of the project.
#### Other
Append `v` to pass the `vsproj=yes` parameter to the build script. This will generate Visual Studio project files.\
Append `c` to pass the `compiledb=yes` parameter to the build script. This is a new feature in 3.x to have this disabled by default to lessen compile times.
#### Postfixes
There are a few postfixes for the build words. These are more complex options. You have to append them to your build word with an underscore.
You can use as many as you want.
For example:
``` scons bel_slim_latomic -j4 ```
##### slim
With this postfix you can build a slimmed down version of the engine. This disables quite a few unneeded modules.
``` scons bel_slim -j4 ```
##### latomic
If you get linker errors while building the game/editor about undefined referenced with atomic related functions you can use this postfix.
It will add the ` -latomic ` command line switch to the linker flags.
I ran into this issue while building on a raspberry pi 4 with the x11 platform. It might be related to the recent reworks to threading.
``` scons bel_latomic -j4 ```
##### strip
Appends `debug_symbols=no` to the build command, which will strip the resulting binary from debug symbols.
``` scons bel_strip -j4 ```
##### threads
Appends `threads_enabled=yes` to the build command. Useful for building the editor for html.
``` scons bej_threads -j4 ```
#### Scons cache, and sdk locations
In order to use scons cache and to tell the build system where some of the required sdks are located you usually
have to use environment variables. Most of the time you might just want to add them globally,
howewer this is sometimes unfeasible (e.g. you don't have administrator access, or you just want to have
multiple sdk versions installed).
In order to solve this a build config file was added.
If you want to use the config simply rename the provided `build.config.example` to `build.config`, and customize
the settings inside.
### Manual Setup
If you you don't want to use the setup script (or just want to know what it actually does),
this section will explain how to set everything up manually.
First clone the engine:
``` git clone https://github.com/Relintai/pandemonium_engine ```
Now if you look at the [HEADS file](https://github.com/Relintai/broken_seals/blob/master/HEADS).
It contains the commit hashes for that particular revision for every module and the engine.
The engine now contains all the modules, so at the moment only worry about the engine's commit hash.
You need to go and checkout the proper commit for it.
Now you can go ahead and compile the engine normally.
## Pulling upstream changes
First pull the changes by calling
``` git pull orgin master ```
Then just run `scons`, to will update the modules.
## Upgrading the modules
Note: this is how to update the HEADS file. Normally you don't need to do this.
If you want to update the modules, and the engine to the latest, you can use (`action=update`):
``` scons a=u ```
You can also update different targets: `all`, `engine`, `modules`, `all_addons`, `addons`, `third_party_addons`
For example to update the engine to the latest: ``` scons a=u target=engine ```

View File

@ -0,0 +1,7 @@
[plugin]
name="WorldGenerator"
description=""
author="Relintai"
version=""
script="plugin.gd"

View File

@ -0,0 +1,77 @@
tool
extends EditorPlugin
var SWorldGeneratorSettings = preload("res://addons/world_generator/resources/world_generator_settings.gd")
var SWorldGenBaseResource = preload("res://addons/world_generator/resources/world_gen_base_resource.gd")
var SWorldGenWorld = preload("res://addons/world_generator/resources/world_gen_world.gd")
var SContinent = preload("res://addons/world_generator/resources/continent.gd")
var SZone = preload("res://addons/world_generator/resources/zone.gd")
var SSubZone = preload("res://addons/world_generator/resources/subzone.gd")
var editor_packed_scene = preload("res://addons/world_generator/ui/MainScreen.tscn")
var editor_scene = null
var tool_button : ToolButton = null
func _enter_tree():
add_custom_type("WorldGeneratorSettings", "Resource", SWorldGeneratorSettings, null)
add_custom_type("WorldGenBaseResource", "Resource", SWorldGenBaseResource, null)
#Don't change the base to "WorldGenBaseResource" else it will complain about a non-existant class
#Also it works perfectly like this
add_custom_type("WorldGenWorld", "Resource", SWorldGenWorld, null)
add_custom_type("Continent", "Resource", SContinent, null)
add_custom_type("Zone", "Resource", SZone, null)
add_custom_type("SubZone", "Resource", SSubZone, null)
editor_scene = editor_packed_scene.instance()
editor_scene.set_plugin(self)
tool_button = add_control_to_bottom_panel(editor_scene, "World Editor")
tool_button.hide()
func _exit_tree():
remove_custom_type("WorldGeneratorSettings")
remove_custom_type("WorldGenBaseResource")
remove_custom_type("WorldGenWorld")
remove_custom_type("Continent")
remove_custom_type("Zone")
remove_custom_type("SubZone")
remove_control_from_bottom_panel(editor_scene)
func handles(object):
return object is WorldGenWorld
func edit(object):
#if editor_scene:
# make_bottom_panel_item_visible(editor_scene)
if object is WorldGenWorld:
var wgw : WorldGenWorld = object as WorldGenWorld
editor_scene.set_wgworld(wgw)
func make_visible(visible):
if tool_button:
if visible:
tool_button.show()
else:
#if tool_button.pressed:
# tool_button.pressed = false
if !tool_button.pressed:
tool_button.hide()
func get_plugin_icon():
return null
func get_plugin_name():
return "WorldGeneratorEditor"
func has_main_screen():
return false

View File

@ -0,0 +1,32 @@
tool
extends Reference
class_name WorldGenRaycast
var current_index : int = -1
var base_resources : Array = Array()
var local_positions : PoolVector2Array = PoolVector2Array()
var local_uvs : PoolVector2Array = PoolVector2Array()
func get_local_position() -> Vector2:
return local_positions[current_index]
func get_local_uv() -> Vector2:
return local_uvs[current_index]
# WorldGenBaseResource (can't explicitly add -> cyclic dependency)
func get_resource():
return base_resources[current_index]
func next() -> bool:
current_index += 1
return base_resources.size() > current_index
func size() -> int:
return base_resources.size()
# base_resource -> WorldGenBaseResource
func add_data(base_resource, local_pos : Vector2, local_uv : Vector2) -> void:
base_resources.append(base_resource)
local_positions.append(local_pos)
local_uvs.append(local_uv)

View File

@ -0,0 +1,38 @@
tool
extends "res://addons/world_generator/resources/world_gen_base_resource.gd"
class_name Continent
export(Array) var zones : Array
func get_content() -> Array:
return zones
func set_content(arr : Array) -> void:
zones = arr
func create_content(item_name : String = "") -> void:
var zone : Zone = Zone.new()
zone.resource_name = item_name
var r : Rect2 = get_rect()
r.position = Vector2()
r.size.x /= 10.0
r.size.y /= 10.0
zone.set_rect(r)
add_content(zone)
func add_content(entry : WorldGenBaseResource) -> void:
zones.append(entry)
emit_changed()
func remove_content_entry(entry : WorldGenBaseResource) -> void:
for i in range(zones.size()):
if zones[i] == entry:
zones.remove(i)
emit_changed()
return
func setup_property_inspector(inspector) -> void:
.setup_property_inspector(inspector)

View File

@ -0,0 +1,7 @@
tool
extends "res://addons/world_generator/resources/world_gen_base_resource.gd"
class_name SubZoneProp
func setup_property_inspector(inspector) -> void:
.setup_property_inspector(inspector)

View File

@ -0,0 +1,38 @@
tool
extends "res://addons/world_generator/resources/world_gen_base_resource.gd"
class_name SubZone
export(Array) var subzone_props : Array
func get_content() -> Array:
return subzone_props
func set_content(arr : Array) -> void:
subzone_props = arr
func create_content(item_name : String = "") -> void:
var subzone_prop : SubZoneProp = SubZoneProp.new()
subzone_prop.resource_name = item_name
var r : Rect2 = get_rect()
r.position = Vector2()
r.size.x /= 10.0
r.size.y /= 10.0
subzone_prop.set_rect(r)
add_content(subzone_prop)
func add_content(entry : WorldGenBaseResource) -> void:
subzone_props.append(entry)
emit_changed()
func remove_content_entry(entry : WorldGenBaseResource) -> void:
for i in range(subzone_props.size()):
if subzone_props[i] == entry:
subzone_props.remove(i)
emit_changed()
return
func setup_property_inspector(inspector) -> void:
.setup_property_inspector(inspector)

View File

@ -0,0 +1,219 @@
tool
extends Resource
class_name WorldGenBaseResource
export(Rect2) var rect : Rect2 = Rect2(0, 0, 100, 100)
export(Vector2i) var min_size : Vector2i = Vector2i(1, 1)
export(Vector2i) var max_size : Vector2i = Vector2i(1000000, 1000000)
export(bool) var locked : bool = false
func get_rect() -> Rect2:
return rect
func set_rect(r : Rect2) -> void:
rect.position = r.position
rect.size.x = max(min_size.x, r.size.x)
rect.size.y = max(min_size.y, r.size.y)
rect.size.x = min(max_size.x, rect.size.x)
rect.size.y = min(max_size.y, rect.size.y)
emit_changed()
func get_min_size() -> Vector2i:
return min_size
func set_min_size(r : Vector2i) -> void:
min_size = r
emit_changed()
func get_max_size() -> Vector2i:
return max_size
func set_max_size(r : Vector2i) -> void:
max_size = r
emit_changed()
func get_locked() -> bool:
return locked
func set_locked(r : bool) -> void:
locked = r
emit_changed()
func get_content() -> Array:
return Array()
func set_content(arr : Array) -> void:
pass
func add_content(entry : WorldGenBaseResource) -> void:
pass
func create_content(item_name : String = "") -> void:
pass
func remove_content_entry(entry : WorldGenBaseResource) -> void:
pass
func is_spawner() -> bool:
return _is_spawner()
func _is_spawner() -> bool:
return false
func get_spawn_local_position() -> Vector2:
return _get_spawn_local_position()
func _get_spawn_local_position() -> Vector2:
return Vector2()
func get_spawn_positions(var parent_position : Vector2 = Vector2()) -> Array:
if is_spawner():
return [ [ resource_name, parent_position + rect.position + get_spawn_local_position() ] ]
var spawners : Array
var p : Vector2 = parent_position + rect.position
for c in get_content():
if c:
spawners.append_array(c.get_spawn_positions(p))
return spawners
func get_content_with_name(name : String) -> WorldGenBaseResource:
if resource_name == name:
return self
for c in get_content():
if c:
var cc = c.get_content_with_name(name)
if cc:
return cc
return null
func get_all_contents_with_name(name : String) -> Array:
var arr : Array = Array()
if resource_name == name:
arr.append(self)
for c in get_content():
if c:
var cc : Array = c.get_all_contents_with_name(name)
arr.append_array(cc)
return arr
func duplicate_content_entry(entry : WorldGenBaseResource, add : bool = true) -> WorldGenBaseResource:
var de : WorldGenBaseResource = entry.duplicate(true)
de.resource_name += " (Duplicate)"
if add:
add_content(de)
return de
func setup_terra_library(library : TerrainLibrary, pseed : int) -> void:
_setup_terra_library(library, pseed)
for c in get_content():
if c:
c.setup_terra_library(library, pseed)
func _setup_terra_library(library : TerrainLibrary, pseed : int) -> void:
pass
func generate_terra_chunk(chunk: TerrainChunk, pseed : int, spawn_mobs: bool) -> void:
var p : Vector2 = Vector2(chunk.get_position_x(), chunk.get_position_z())
var raycast : WorldGenRaycast = get_hit_stack(p)
if raycast.size() == 0:
_generate_terra_chunk_fallback(chunk, pseed, spawn_mobs)
return
while raycast.next():
raycast.get_resource()._generate_terra_chunk(chunk, pseed, spawn_mobs, raycast)
func _generate_terra_chunk(chunk: TerrainChunk, pseed : int, spawn_mobs: bool, raycast : WorldGenRaycast) -> void:
pass
func _generate_terra_chunk_fallback(chunk: TerrainChunk, pseed : int, spawn_mobs: bool) -> void:
chunk.channel_ensure_allocated(TerrainChunkDefault.DEFAULT_CHANNEL_TYPE, 1)
chunk.channel_ensure_allocated(TerrainChunkDefault.DEFAULT_CHANNEL_ISOLEVEL, 1)
chunk.set_voxel(1, 0, 0, TerrainChunkDefault.DEFAULT_CHANNEL_ISOLEVEL)
func generate_map(pseed : int) -> Image:
var img : Image = Image.new()
img.create(get_rect().size.x, get_rect().size.y, false, Image.FORMAT_RGBA8)
add_to_map(img, pseed)
return img
func add_to_map(img : Image, pseed : int) -> void:
_add_to_map(img, pseed)
for c in get_content():
if c:
c.add_to_map(img, pseed)
func _add_to_map(img : Image, pseed : int) -> void:
pass
func get_hit_stack(pos : Vector2, raycast : WorldGenRaycast = null) -> WorldGenRaycast:
var r : Rect2 = get_rect()
var local_pos : Vector2 = pos - rect.position
r.position = Vector2()
if !raycast:
raycast = WorldGenRaycast.new()
if r.has_point(local_pos):
var local_uv : Vector2 = local_pos / rect.size
raycast.add_data(self, local_pos, local_uv)
for c in get_content():
if c:
c.get_hit_stack(local_pos, raycast)
return raycast
func get_editor_rect_border_color() -> Color:
return Color(1, 1, 1, 1)
func get_editor_rect_color() -> Color:
return Color(1, 1, 1, 0.9)
func get_editor_rect_border_size() -> int:
return 2
func get_editor_font_color() -> Color:
return Color(0, 0, 0, 1)
func get_editor_class() -> String:
return "WorldGenBaseResource"
func get_editor_additional_text() -> String:
return ""
func eitor_draw_additional(control : Control) -> void:
_eitor_draw_additional(control)
func _eitor_draw_additional(control : Control) -> void:
pass
func eitor_draw_additional_background(control : Control) -> void:
_eitor_draw_additional_background(control)
func _eitor_draw_additional_background(control : Control) -> void:
pass
func setup_property_inspector(inspector) -> void:
inspector.add_slot_line_edit("get_name", "set_name", "Name")
inspector.add_slot_rect2("get_rect", "set_rect", "Rect", 1)
inspector.add_slot_vector2i("get_min_size", "set_min_size", "Min Size", 1)
inspector.add_slot_vector2i("get_max_size", "set_max_size", "Max Size", 1)
inspector.add_slot_bool("get_locked", "set_locked", "Locked")

View File

@ -0,0 +1,62 @@
tool
extends "res://addons/world_generator/resources/world_gen_base_resource.gd"
class_name WorldGenWorld
export(Array) var continents : Array
func get_content() -> Array:
return continents
func set_content(arr : Array) -> void:
continents = arr
func create_content(item_name : String = "") -> void:
var continent : Continent = Continent.new()
continent.resource_name = item_name
add_content(continent)
func add_content(entry : WorldGenBaseResource) -> void:
var r : Rect2 = get_rect()
r.position = Vector2()
r.size.x /= 10.0
r.size.y /= 10.0
entry.set_rect(r)
continents.append(entry)
emit_changed()
func remove_content_entry(entry : WorldGenBaseResource) -> void:
for i in range(continents.size()):
if continents[i] == entry:
continents.remove(i)
emit_changed()
return
func setup_property_inspector(inspector) -> void:
.setup_property_inspector(inspector)
func generate_terra_chunk(chunk: TerrainChunk, pseed : int, spawn_mobs: bool) -> void:
var p : Vector2 = Vector2(chunk.get_position_x(), chunk.get_position_z())
var raycast : WorldGenRaycast = get_hit_stack(p)
if raycast.size() == 0:
_generate_terra_chunk_fallback(chunk, pseed, spawn_mobs)
return
_generate_terra_chunk(chunk, pseed, spawn_mobs, raycast)
while raycast.next():
raycast.get_resource()._generate_terra_chunk(chunk, pseed, spawn_mobs, raycast)
func _generate_terra_chunk(chunk: TerrainChunk, pseed : int, spawn_mobs: bool, raycast : WorldGenRaycast) -> void:
pass
func _generate_terra_chunk_fallback(chunk: TerrainChunk, pseed : int, spawn_mobs: bool) -> void:
chunk.channel_ensure_allocated(TerrainChunkDefault.DEFAULT_CHANNEL_TYPE, 1)
chunk.channel_ensure_allocated(TerrainChunkDefault.DEFAULT_CHANNEL_ISOLEVEL, 1)
chunk.set_voxel(1, 0, 0, TerrainChunkDefault.DEFAULT_CHANNEL_ISOLEVEL)

View File

@ -0,0 +1,104 @@
tool
extends Resource
class_name WorldGeneratorSettings
export(PoolStringArray) var continent_class_folders : PoolStringArray
export(PoolStringArray) var zone_class_folders : PoolStringArray
export(PoolStringArray) var subzone_class_folders : PoolStringArray
export(PoolStringArray) var subzone_prop_class_folders : PoolStringArray
enum WorldGeneratorScriptType {
CONTINENT = 0,
ZONE = 1,
SUBZONE = 2,
SUBZONE_PROP = 3,
};
func evaluate_scripts(script_type : int, tree : Tree) -> void:
if (script_type == WorldGeneratorScriptType.CONTINENT):
evaluate_continent_scripts(tree)
elif (script_type == WorldGeneratorScriptType.ZONE):
evaluate_zone_scripts(tree)
elif (script_type == WorldGeneratorScriptType.SUBZONE):
evaluate_subzone_scripts(tree)
elif (script_type == WorldGeneratorScriptType.SUBZONE_PROP):
evaluate_subzone_prop_scripts(tree)
func evaluate_continent_scripts(tree : Tree) -> void:
tree.clear()
var root : TreeItem = tree.create_item()
root.set_text(0, "Continent")
root.set_meta("class_name", "Continent")
for s in continent_class_folders:
evaluate_folder(s, tree, root)
root.select(0)
func evaluate_zone_scripts(tree : Tree) -> void:
tree.clear()
var root : TreeItem = tree.create_item()
root.set_text(0, "Zone")
root.set_meta("class_name", "Zone")
for s in zone_class_folders:
evaluate_folder(s, tree, root)
root.select(0)
func evaluate_subzone_scripts(tree : Tree) -> void:
tree.clear()
var root : TreeItem = tree.create_item()
root.set_text(0, "SubZone")
root.set_meta("class_name", "SubZone")
for s in subzone_class_folders:
evaluate_folder(s, tree, root)
root.select(0)
func evaluate_subzone_prop_scripts(tree : Tree) -> void:
tree.clear()
var root : TreeItem = tree.create_item()
root.set_text(0, "SubZoneProp")
root.set_meta("class_name", "SubZoneProp")
for s in subzone_prop_class_folders:
evaluate_folder(s, tree, root)
root.select(0)
func evaluate_folder(folder : String, tree : Tree, root : TreeItem) -> void:
var ti : TreeItem = null
var dir = Directory.new()
if dir.open(folder) == OK:
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name != "":
if !dir.current_is_dir():
#print("Found file: " + file_name)
if !ti:
var n : String = folder.substr(folder.find_last("/") + 1)
if n != "":
ti = tree.create_item(root)
ti.set_text(0, n)
else:
ti = root
var e : TreeItem = tree.create_item(ti)
e.set_text(0, file_name.get_file())
e.set_meta("file", folder + "/" + file_name)
file_name = dir.get_next()
else:
print("An error occurred when trying to access the path.")

View File

@ -0,0 +1,38 @@
tool
extends "res://addons/world_generator/resources/world_gen_base_resource.gd"
class_name Zone
export(Array) var subzones : Array
func get_content() -> Array:
return subzones
func set_content(arr : Array) -> void:
subzones = arr
func create_content(item_name : String = "") -> void:
var subzone : SubZone = SubZone.new()
subzone.resource_name = item_name
var r : Rect2 = get_rect()
r.position = Vector2()
r.size.x /= 10.0
r.size.y /= 10.0
subzone.set_rect(r)
add_content(subzone)
func add_content(entry : WorldGenBaseResource) -> void:
subzones.append(entry)
emit_changed()
func remove_content_entry(entry : WorldGenBaseResource) -> void:
for i in range(subzones.size()):
if subzones[i] == entry:
subzones.remove(i)
emit_changed()
return
func setup_property_inspector(inspector) -> void:
.setup_property_inspector(inspector)

View File

@ -0,0 +1,351 @@
[gd_resource type="Resource" load_steps=40 format=2]
[ext_resource path="res://addons/world_generator/resources/world_gen_world.gd" type="Script" id=1]
[ext_resource path="res://addons/world_generator/resources/continent.gd" type="Script" id=2]
[ext_resource path="res://addons/world_generator/resources/zone.gd" type="Script" id=3]
[ext_resource path="res://addons/world_generator/resources/subzone.gd" type="Script" id=4]
[ext_resource path="res://scripts/world_generator/continents/test_continent.gd" type="Script" id=5]
[ext_resource path="res://scripts/world_generator/zones/test_zone.gd" type="Script" id=6]
[ext_resource path="res://scripts/world_generator/subzones/test_subzone.gd" type="Script" id=7]
[sub_resource type="Resource" id=14]
resource_name = "qwe"
script = ExtResource( 4 )
rect = Rect2( 21, 25, 150, 79 )
locked = false
[sub_resource type="Resource" id=15]
resource_name = "we"
script = ExtResource( 4 )
rect = Rect2( 7, 9, 54, 34 )
locked = false
[sub_resource type="Resource" id=34]
resource_name = "yy"
script = ExtResource( 7 )
rect = Rect2( 66, 11, 100, 91 )
locked = false
[sub_resource type="Resource" id=8]
resource_name = "asdasr"
script = ExtResource( 3 )
rect = Rect2( 35, 21, 191.4, 127.8 )
locked = false
subzones = [ SubResource( 14 ), SubResource( 15 ), SubResource( 34 ) ]
[sub_resource type="Resource" id=13]
resource_name = "qqq"
script = ExtResource( 3 )
rect = Rect2( 17, 59, 200.4, 52 )
locked = false
subzones = [ ]
[sub_resource type="Resource" id=24]
resource_name = "trtrtr"
script = ExtResource( 3 )
rect = Rect2( 0, 0, 57.1, 45.8 )
locked = false
subzones = [ ]
[sub_resource type="GDScript" id=25]
script/source = "tool
extends \"res://addons/world_generator/resources/world_gen_base_resource.gd\"
class_name Zone
export(Array) var subzones : Array
func get_content() -> Array:
return subzones
func set_content(arr : Array) -> void:
subzones = arr
func create_content(item_name : String = \"\") -> void:
var subzone : SubZone = SubZone.new()
subzone.resource_name = item_name
var r : Rect2 = get_rect()
r.position = Vector2()
r.size.x /= 10.0
r.size.y /= 10.0
subzone.set_rect(r)
add_content(subzone)
func add_content(entry : WorldGenBaseResource) -> void:
subzones.append(entry)
emit_changed()
func remove_content_entry(entry : WorldGenBaseResource) -> void:
for i in range(subzones.size()):
if subzones[i] == entry:
subzones.remove(i)
emit_changed()
return
func setup_property_inspector(inspector) -> void:
.setup_property_inspector(inspector)
"
[sub_resource type="Resource" id=26]
resource_name = "trtrtr (Duplicate)"
script = SubResource( 25 )
rect = Rect2( 64, 6, 158.1, 39.8 )
locked = false
subzones = [ ]
[sub_resource type="Resource" id=32]
resource_name = "tttte"
script = ExtResource( 3 )
rect = Rect2( 103, 28, 100, 100 )
locked = false
subzones = [ ]
[sub_resource type="Resource" id=35]
resource_name = "yu"
script = ExtResource( 6 )
rect = Rect2( 88, 21, 100, 100 )
locked = false
subzones = [ ]
[sub_resource type="Resource" id=1]
resource_name = "wwww"
script = ExtResource( 2 )
rect = Rect2( 163, 35, 241, 158 )
zones = [ SubResource( 8 ), SubResource( 13 ), SubResource( 24 ), SubResource( 26 ), SubResource( 32 ), SubResource( 35 ) ]
[sub_resource type="Resource" id=2]
resource_name = "efefef"
script = ExtResource( 2 )
rect = Rect2( 107, 271, 100, 49 )
[sub_resource type="Resource" id=3]
resource_name = "grgrg"
script = ExtResource( 2 )
rect = Rect2( 498, 185, 100, 100 )
[sub_resource type="Resource" id=9]
resource_name = "asd"
script = ExtResource( 3 )
rect = Rect2( 528, 34, 0, 0 )
locked = false
subzones = [ ]
[sub_resource type="Resource" id=10]
resource_name = "qqq"
script = ExtResource( 3 )
rect = Rect2( 528, 34, 0, 0 )
locked = false
subzones = [ ]
[sub_resource type="Resource" id=4]
resource_name = "qwdasd"
script = ExtResource( 2 )
rect = Rect2( 522, 29, 63, 54 )
zones = [ SubResource( 9 ), SubResource( 10 ) ]
[sub_resource type="Resource" id=11]
resource_name = "q"
script = ExtResource( 3 )
rect = Rect2( 14, 11, 53, 59 )
locked = false
subzones = [ ]
[sub_resource type="Resource" id=5]
resource_name = "qwe"
script = ExtResource( 2 )
rect = Rect2( 473, 331, 100, 100 )
zones = [ SubResource( 11 ) ]
[sub_resource type="GDScript" id=16]
script/source = "tool
extends \"res://addons/world_generator/resources/world_gen_base_resource.gd\"
class_name Continent
export(Array) var zones : Array
func get_content() -> Array:
return zones
func set_content(arr : Array) -> void:
zones = arr
func create_content(item_name : String = \"\") -> void:
var zone : Zone = Zone.new()
zone.resource_name = item_name
var r : Rect2 = get_rect()
r.position = Vector2()
r.size.x /= 10.0
r.size.y /= 10.0
zone.set_rect(r)
add_content(zone)
func add_content(entry : WorldGenBaseResource) -> void:
zones.append(entry)
emit_changed()
func remove_content_entry(entry : WorldGenBaseResource) -> void:
for i in range(zones.size()):
if zones[i] == entry:
zones.remove(i)
emit_changed()
return
func setup_property_inspector(inspector) -> void:
.setup_property_inspector(inspector)
"
[sub_resource type="Resource" id=17]
resource_name = "qwetwwqasd"
script = SubResource( 16 )
rect = Rect2( 473, 331, 100, 100 )
locked = false
zones = [ SubResource( 11 ) ]
[sub_resource type="GDScript" id=18]
script/source = "tool
extends \"res://addons/world_generator/resources/world_gen_base_resource.gd\"
class_name Continent
export(Array) var zones : Array
func get_content() -> Array:
return zones
func set_content(arr : Array) -> void:
zones = arr
func create_content(item_name : String = \"\") -> void:
var zone : Zone = Zone.new()
zone.resource_name = item_name
var r : Rect2 = get_rect()
r.position = Vector2()
r.size.x /= 10.0
r.size.y /= 10.0
zone.set_rect(r)
add_content(zone)
func add_content(entry : WorldGenBaseResource) -> void:
zones.append(entry)
emit_changed()
func remove_content_entry(entry : WorldGenBaseResource) -> void:
for i in range(zones.size()):
if zones[i] == entry:
zones.remove(i)
emit_changed()
return
func setup_property_inspector(inspector) -> void:
.setup_property_inspector(inspector)
"
[sub_resource type="Resource" id=19]
resource_name = "qwesat"
script = SubResource( 18 )
rect = Rect2( 613, 346, 100, 100 )
locked = false
zones = [ SubResource( 11 ) ]
[sub_resource type="Resource" id=20]
resource_name = "ggg"
script = ExtResource( 2 )
rect = Rect2( 26, 51, 100, 100 )
[sub_resource type="GDScript" id=21]
script/source = "tool
extends \"res://addons/world_generator/resources/world_gen_base_resource.gd\"
class_name Continent
export(Array) var zones : Array
func get_content() -> Array:
return zones
func set_content(arr : Array) -> void:
zones = arr
func create_content(item_name : String = \"\") -> void:
var zone : Zone = Zone.new()
zone.resource_name = item_name
var r : Rect2 = get_rect()
r.position = Vector2()
r.size.x /= 10.0
r.size.y /= 10.0
zone.set_rect(r)
add_content(zone)
func add_content(entry : WorldGenBaseResource) -> void:
zones.append(entry)
emit_changed()
func remove_content_entry(entry : WorldGenBaseResource) -> void:
for i in range(zones.size()):
if zones[i] == entry:
zones.remove(i)
emit_changed()
return
func setup_property_inspector(inspector) -> void:
.setup_property_inspector(inspector)
"
[sub_resource type="Resource" id=22]
resource_name = "ggg (Duplicate)"
script = SubResource( 21 )
rect = Rect2( 33, 181, 100, 100 )
locked = false
zones = [ ]
[sub_resource type="Resource" id=23]
resource_name = "eeqqq"
script = ExtResource( 2 )
rect = Rect2( 256, 365, 100, 100 )
[sub_resource type="Resource" id=27]
resource_name = "asd"
script = ExtResource( 2 )
rect = Rect2( 337, 79, 100, 100 )
[sub_resource type="Resource" id=28]
resource_name = "asd"
script = ExtResource( 2 )
rect = Rect2( 244, 234, 100, 100 )
[sub_resource type="Resource" id=29]
script = ExtResource( 2 )
rect = Rect2( 377, 69, 284, 238 )
[sub_resource type="Resource" id=30]
resource_name = "tttttt"
script = ExtResource( 2 )
rect = Rect2( 188, 225, 233, 259 )
[sub_resource type="Resource" id=31]
resource_name = "ttttyuqtttt"
script = ExtResource( 2 )
rect = Rect2( 339, 76, 220, 170 )
[sub_resource type="Resource" id=33]
resource_name = "qttt"
script = ExtResource( 5 )
rect = Rect2( 99, 78, 213, 105 )
locked = false
zones = [ ]
[resource]
resource_name = "asdasdsse"
script = ExtResource( 1 )
rect = Rect2( 0, 0, 1000, 1000 )
locked = false
continents = [ SubResource( 1 ), SubResource( 2 ), SubResource( 3 ), SubResource( 4 ), SubResource( 5 ), SubResource( 17 ), SubResource( 19 ), SubResource( 20 ), SubResource( 22 ), SubResource( 23 ), SubResource( 27 ), SubResource( 28 ), SubResource( 29 ), SubResource( 30 ), SubResource( 31 ), SubResource( 33 ) ]

View File

@ -0,0 +1,201 @@
tool
extends Tree
export(int, "Continent,Zone,Sub Zone,Sub Zone Prop") var class_types : int = 0
var edited_resource : WorldGenBaseResource = null
var name_edited_resource : WorldGenBaseResource = null
var _ignore_changed_event : bool = false
var _plugin : EditorPlugin = null
var _undo_redo : UndoRedo = null
signal request_item_edit(world_gen_base_resource)
func _init():
if !is_connected("item_edited", self, "on_item_edited"):
connect("item_edited", self, "on_item_edited")
if !is_connected("button_pressed", self, "on_tree_button_pressed"):
connect("button_pressed", self, "on_tree_button_pressed")
func set_plugin(plugin : EditorPlugin) -> void:
_plugin = plugin
_undo_redo = _plugin.get_undo_redo()
func _enter_tree():
var dir : Directory = Directory.new()
if dir.file_exists("res://world_generator_settings.tres"):
var wgs : WorldGeneratorSettings = load("res://world_generator_settings.tres") as WorldGeneratorSettings
if !wgs:
return
wgs.evaluate_scripts(class_types, $NameDialog/VBoxContainer/Tree)
func add_item(item_name : String = "") -> void:
if !edited_resource:
return
var ti : TreeItem = $NameDialog/VBoxContainer/Tree.get_selected()
if !ti:
return
var e : WorldGenBaseResource = null
if ti.has_meta("class_name"):
var cn : String = ti.get_meta("class_name")
if cn == "Continent":
e = Continent.new()
elif cn == "Zone":
e = Zone.new()
elif cn == "SubZone":
e = SubZone.new()
elif cn == "SubZoneProp":
e = SubZoneProp.new()
elif ti.has_meta("file"):
var cls = load(ti.get_meta("file"))
if cls:
e = cls.new()
if !e:
return
e.resource_name = item_name
var r : Rect2 = edited_resource.get_rect()
var rs : Vector2 = r.size
r.size.x /= 5.0
r.size.y /= 5.0
r.position = rs / Vector2(2, 2)
r.position -= r.size / Vector2(2, 2)
e.set_rect(r)
#edited_resource.add_content(e)
#remove_content_entry
_undo_redo.create_action("WE: Created Entry")
_undo_redo.add_do_method(edited_resource, "add_content", e)
_undo_redo.add_undo_method(edited_resource, "remove_content_entry", e)
_undo_redo.commit_action()
func refresh() -> void:
clear()
if !edited_resource:
return
var root : TreeItem = create_item()
var data : Array = edited_resource.get_content()
for d in data:
if d:
var n : String = d.resource_name
if n == "":
n = "<no name>"
var item : TreeItem = create_item(root)
item.set_text(0, n)
item.set_meta("res", d)
item.add_button(0, get_theme_icon("Edit", "EditorIcons"), -1, false, "Edit")
item.set_editable(0, true)
func set_edited_resource(res : WorldGenBaseResource)-> void:
if edited_resource:
edited_resource.disconnect("changed", self, "on_resource_changed")
edited_resource = res
if edited_resource:
edited_resource.connect("changed", self, "on_resource_changed")
refresh()
func add_button_pressed() -> void:
$NameDialog/VBoxContainer/LineEdit.text = ""
$NameDialog.popup_centered()
func name_dialog_ok_pressed() -> void:
add_item($NameDialog/VBoxContainer/LineEdit.text)
func delete_button_pressed() -> void:
var item : TreeItem = get_selected()
if !item:
return
var item_resource = item.get_meta("res")
if !item_resource:
return
#edited_resource.remove_content_entry(item_resource)
_undo_redo.create_action("WE: Created Entry")
_undo_redo.add_do_method(edited_resource, "remove_content_entry", item_resource)
_undo_redo.add_undo_method(edited_resource, "add_content", item_resource)
_undo_redo.commit_action()
func duplicate_button_pressed() -> void:
var item : TreeItem = get_selected()
if !item:
return
var item_resource = item.get_meta("res")
if !item_resource:
return
#edited_resource.duplicate_content_entry(item_resource)
var de = edited_resource.duplicate_content_entry(item_resource, false)
_undo_redo.create_action("WE: Created Entry")
_undo_redo.add_do_method(edited_resource, "add_content", de)
_undo_redo.add_undo_method(edited_resource, "remove_content_entry", de)
_undo_redo.commit_action()
func on_resource_changed() -> void:
if _ignore_changed_event:
return
call_deferred("refresh")
func on_tree_button_pressed(item: TreeItem, column: int, id: int) -> void:
var resource : WorldGenBaseResource = item.get_meta("res")
if !resource:
return
emit_signal("request_item_edit", resource)
func on_item_edited() -> void:
var item : TreeItem = get_edited()
if !item:
return
name_edited_resource = item.get_meta("res")
if !name_edited_resource:
return
_undo_redo.create_action("WE: Renamed Entry")
_undo_redo.add_do_method(name_edited_resource, "set_name", item.get_text(0))
_undo_redo.add_undo_method(name_edited_resource, "set_name", name_edited_resource.resource_name)
_undo_redo.commit_action()
# name_edited_resource.resource_name = item.get_text(0)
name_edited_resource.emit_changed()
name_edited_resource = null
on_resource_changed()

View File

@ -0,0 +1,57 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/world_generator/ui/DataList.gd" type="Script" id=1]
[node name="DataList" type="Tree"]
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
size_flags_vertical = 3
allow_reselect = true
hide_folding = true
hide_root = true
script = ExtResource( 1 )
[node name="NameDialog" type="ConfirmationDialog" parent="."]
margin_right = 329.0
margin_bottom = 313.0
window_title = "Name"
resizable = true
__meta__ = {
"_edit_use_anchors_": false
}
[node name="VBoxContainer" type="VBoxContainer" parent="NameDialog"]
margin_left = 8.0
margin_top = 8.0
margin_right = 321.0
margin_bottom = 277.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label2" type="Label" parent="NameDialog/VBoxContainer"]
margin_right = 313.0
margin_bottom = 14.0
text = "Class"
[node name="Tree" type="Tree" parent="NameDialog/VBoxContainer"]
margin_top = 18.0
margin_right = 313.0
margin_bottom = 223.0
rect_min_size = Vector2( 0, 200 )
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Label" type="Label" parent="NameDialog/VBoxContainer"]
margin_top = 227.0
margin_right = 313.0
margin_bottom = 241.0
text = "Name"
[node name="LineEdit" type="LineEdit" parent="NameDialog/VBoxContainer"]
margin_top = 245.0
margin_right = 313.0
margin_bottom = 269.0
[connection signal="confirmed" from="NameDialog" to="." method="name_dialog_ok_pressed"]

View File

@ -0,0 +1,73 @@
tool
extends PanelContainer
var edited_world
func _ready():
var world : Control = get_node("TabContainer/World")
if !world.is_connected("request_item_edit", self, "on_world_request_item_edit"):
world.connect("request_item_edit", self, "on_world_request_item_edit")
var continent : Control = get_node("TabContainer/Continent")
if !continent.is_connected("request_item_edit", self, "on_continent_request_item_edit"):
continent.connect("request_item_edit", self, "on_continent_request_item_edit")
var zone : Control = get_node("TabContainer/Zone")
if !zone.is_connected("request_item_edit", self, "on_zone_request_item_edit"):
zone.connect("request_item_edit", self, "on_zone_request_item_edit")
var subzone : Control = get_node("TabContainer/SubZone")
if !subzone.is_connected("request_item_edit", self, "on_subzone_request_item_edit"):
subzone.connect("request_item_edit", self, "on_subzone_request_item_edit")
func set_plugin(plugin : EditorPlugin) -> void:
$TabContainer/World.set_plugin(plugin)
$TabContainer/Continent.set_plugin(plugin)
$TabContainer/Zone.set_plugin(plugin)
$TabContainer/SubZone.set_plugin(plugin)
$TabContainer/SubZoneProp.set_plugin(plugin)
func refresh() -> void:
$TabContainer/World.set_wgworld(edited_world)
$TabContainer/Continent.set_wgworld(edited_world)
$TabContainer/Zone.set_wgworld(edited_world)
$TabContainer/SubZone.set_wgworld(edited_world)
$TabContainer/SubZoneProp.set_wgworld(edited_world)
func set_wgworld(wgw : WorldGenWorld) -> void:
edited_world = wgw
refresh()
func on_world_request_item_edit(resource : WorldGenBaseResource) -> void:
var cont : Control = get_node("TabContainer/Continent")
var tc : TabContainer = get_node("TabContainer")
tc.current_tab = cont.get_position_in_parent()
cont.switch_to(resource)
func on_continent_request_item_edit(continent : WorldGenBaseResource, resource : WorldGenBaseResource) -> void:
var zone : Control = get_node("TabContainer/Zone")
var tc : TabContainer = get_node("TabContainer")
tc.current_tab = zone.get_position_in_parent()
zone.switch_to(continent, resource)
func on_zone_request_item_edit(continent : WorldGenBaseResource, zone : WorldGenBaseResource, subzone : WorldGenBaseResource) -> void:
var sz : Control = get_node("TabContainer/SubZone")
var tc : TabContainer = get_node("TabContainer")
tc.current_tab = sz.get_position_in_parent()
sz.switch_to(continent, zone, subzone)
func on_subzone_request_item_edit(continent : WorldGenBaseResource, zone : WorldGenBaseResource, subzone : WorldGenBaseResource, subzone_prop : WorldGenBaseResource) -> void:
var sz : Control = get_node("TabContainer/SubZoneProp")
var tc : TabContainer = get_node("TabContainer")
tc.current_tab = sz.get_position_in_parent()
sz.switch_to(continent, zone, subzone, subzone_prop)

View File

@ -0,0 +1,44 @@
[gd_scene load_steps=7 format=2]
[ext_resource path="res://addons/world_generator/ui/MainScreen.gd" type="Script" id=1]
[ext_resource path="res://addons/world_generator/ui/tabs/World.tscn" type="PackedScene" id=2]
[ext_resource path="res://addons/world_generator/ui/tabs/Continent.tscn" type="PackedScene" id=3]
[ext_resource path="res://addons/world_generator/ui/tabs/Zone.tscn" type="PackedScene" id=4]
[ext_resource path="res://addons/world_generator/ui/tabs/SubZone.tscn" type="PackedScene" id=5]
[ext_resource path="res://addons/world_generator/ui/tabs/SubZoneProp.tscn" type="PackedScene" id=6]
[node name="WorldGenerator" type="PanelContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
rect_min_size = Vector2( 0, 200 )
size_flags_vertical = 3
script = ExtResource( 1 )
[node name="TabContainer" type="TabContainer" parent="."]
margin_left = 7.0
margin_top = 7.0
margin_right = 1017.0
margin_bottom = 593.0
tab_align = 0
[node name="World" parent="TabContainer" instance=ExtResource( 2 )]
[node name="Continent" parent="TabContainer" instance=ExtResource( 3 )]
visible = false
margin_left = 4.0
margin_top = 32.0
margin_right = -4.0
margin_bottom = -4.0
[node name="Zone" parent="TabContainer" instance=ExtResource( 4 )]
visible = false
margin_left = 4.0
margin_top = 32.0
margin_right = -4.0
margin_bottom = -4.0
[node name="SubZone" parent="TabContainer" instance=ExtResource( 5 )]
visible = false
[node name="SubZoneProp" parent="TabContainer" instance=ExtResource( 6 )]
visible = false

View File

@ -0,0 +1,34 @@
tool
extends PanelContainer
var last_edited_res : WorldGenBaseResource = null
func set_plugin(plugin : EditorPlugin) -> void:
get_node("ScrollContainer/MarginContainer/RectView").set_plugin(plugin)
func set_edited_resource(res : WorldGenBaseResource):
get_node("ScrollContainer/MarginContainer/RectView").set_edited_resource(res)
if res && res != last_edited_res:
var r : Rect2 = res.get_rect()
last_edited_res = res
var axis : int = 0
if r.size.x > r.size.y:
axis = Vector2.AXIS_X
else:
axis = Vector2.AXIS_Y
if r.size[axis] > 0:
var rsx : float = get_node("ScrollContainer").rect_size[axis]
var scale : float = rsx / r.size[axis] * 0.5
get_node("Control/EditorZoomWidget").zoom = scale
get_node("ScrollContainer/MarginContainer/RectView").apply_zoom()
var sb : ScrollBar = get_node("ScrollContainer").get_h_scrollbar()
sb.ratio = 1
sb = get_node("ScrollContainer").get_v_scrollbar()
sb.ratio = 1

View File

@ -0,0 +1,48 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://addons/world_generator/ui/RectEditor.gd" type="Script" id=1]
[ext_resource path="res://addons/world_generator/widgets/EditorZoomWidget.tscn" type="PackedScene" id=2]
[ext_resource path="res://addons/world_generator/ui/RectView.gd" type="Script" id=3]
[node name="RectEditor" type="PanelContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 1 )
[node name="ScrollContainer" type="ScrollContainer" parent="."]
margin_left = 7.0
margin_top = 7.0
margin_right = 1017.0
margin_bottom = 593.0
[node name="MarginContainer" type="MarginContainer" parent="ScrollContainer"]
margin_right = 400.0
margin_bottom = 400.0
custom_constants/margin_right = 200
custom_constants/margin_top = 200
custom_constants/margin_left = 200
custom_constants/margin_bottom = 200
[node name="RectView" type="Control" parent="ScrollContainer/MarginContainer"]
margin_left = 200.0
margin_top = 200.0
margin_right = 200.0
margin_bottom = 200.0
script = ExtResource( 3 )
zoom_widget_path = NodePath("../../../Control/EditorZoomWidget")
[node name="Control" type="Control" parent="."]
margin_left = 7.0
margin_top = 7.0
margin_right = 1017.0
margin_bottom = 593.0
mouse_filter = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="EditorZoomWidget" parent="Control" instance=ExtResource( 2 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 115.0
margin_bottom = 22.0
custom_constants/separation = -8

View File

@ -0,0 +1,139 @@
tool
extends Control
var rect_editor_node_scene : PackedScene = preload("res://addons/world_generator/ui/RectViewNode.tscn")
export(NodePath) var zoom_widget_path : NodePath = ""
var _rect_scale : float = 1
var edited_resource : WorldGenBaseResource = null
var edited_resource_current_size : Vector2 = Vector2()
var _plugin : EditorPlugin = null
var _undo_redo : UndoRedo = null
func _enter_tree():
var zoom_widget : Node = get_node_or_null(zoom_widget_path)
if !zoom_widget:
return
if !zoom_widget.is_connected("zoom_changed", self, "on_zoom_changed"):
zoom_widget.connect("zoom_changed", self, "on_zoom_changed")
if !is_connected("visibility_changed", self, "on_visibility_changed"):
connect("visibility_changed", self, "on_visibility_changed")
func set_plugin(plugin : EditorPlugin) -> void:
_plugin = plugin
_undo_redo = _plugin.get_undo_redo()
func on_visibility_changed() -> void:
call_deferred("apply_zoom")
func apply_zoom() -> void:
if !edited_resource:
return
var rect : Rect2 = edited_resource.rect
edited_resource_current_size = rect.size
rect.position = rect.position * _rect_scale
rect.size = rect.size * _rect_scale
set_custom_minimum_size(rect.size)
var p : MarginContainer = get_parent() as MarginContainer
p.add_theme_constant_override("margin_left", min(rect.size.x / 4.0, 50 * _rect_scale))
p.add_theme_constant_override("margin_right", min(rect.size.x / 4.0, 50 * _rect_scale))
p.add_theme_constant_override("margin_top", min(rect.size.y / 4.0, 50 * _rect_scale))
p.add_theme_constant_override("margin_bottom", min(rect.size.y / 4.0, 50 * _rect_scale))
for c in get_children():
c.set_editor_rect_scale(_rect_scale)
func on_zoom_changed(zoom : float) -> void:
_rect_scale = zoom
apply_zoom()
func _draw():
draw_rect(Rect2(Vector2(), get_size()), Color(0.2, 0.2, 0.2, 1))
var rsh : float = clamp(_rect_scale / 2.0, 1, 5)
var c : Color = Color(0.4, 0.4, 0.4, 1)
# Indicators that show the size of a unit (1 chunk)
# Top left
draw_line(Vector2(_rect_scale, 0), Vector2(_rect_scale, rsh), c)
draw_line(Vector2(0, _rect_scale), Vector2(rsh, _rect_scale), c)
# Top right
draw_line(Vector2(get_size().x - _rect_scale, 0), Vector2(get_size().x - _rect_scale, rsh), c)
draw_line(Vector2(get_size().x - rsh, _rect_scale), Vector2(get_size().x, _rect_scale), c)
# Bottom left
draw_line(Vector2(_rect_scale, get_size().y - rsh), Vector2(_rect_scale, get_size().y), c)
draw_line(Vector2(0, get_size().y - _rect_scale), Vector2(rsh, get_size().y - _rect_scale), c)
# Bottom right
draw_line(Vector2(get_size().x - _rect_scale, get_size().y - rsh), Vector2(get_size().x - _rect_scale, get_size().y), c)
draw_line(Vector2(get_size().x - rsh, get_size().y - _rect_scale), Vector2(get_size().x, get_size().y - _rect_scale), c)
edited_resource.eitor_draw_additional_background(self)
func refresh() -> void:
clear()
if !edited_resource:
return
var rect : Rect2 = edited_resource.rect
edited_resource_current_size = rect.size
rect.position = rect.position * _rect_scale
rect.size = rect.size * _rect_scale
set_custom_minimum_size(rect.size)
apply_zoom()
refresh_rects()
func clear() -> void:
pass
func refresh_rects() -> void:
clear_rects()
if !edited_resource:
return
var cont : Array = edited_resource.get_content()
for c in cont:
if c:
var s : Node = rect_editor_node_scene.instance()
add_child(s)
s.set_plugin(_plugin)
s.set_editor_rect_scale(_rect_scale)
s.edited_resource_parent_size = edited_resource_current_size
s.set_edited_resource(c)
func clear_rects():
for c in get_children():
c.queue_free()
remove_child(c)
func set_edited_resource(res : WorldGenBaseResource):
if edited_resource:
edited_resource.disconnect("changed", self, "on_edited_resource_changed")
edited_resource = res
refresh()
if edited_resource:
edited_resource.connect("changed", self, "on_edited_resource_changed")
func on_edited_resource_changed() -> void:
call_deferred("refresh")

View File

@ -0,0 +1,232 @@
tool
extends MarginContainer
enum DragType {
DRAG_NONE = 0,
DRAG_MOVE = 1,
DRAG_RESIZE_TOP = 1 << 1,
DRAG_RESIZE_RIGHT = 1 << 2,
DRAG_RESIZE_BOTTOM = 1 << 3,
DRAG_RESIZE_LEFT = 1 << 4
};
var edited_resource : WorldGenBaseResource = null
var edited_resource_parent_size : Vector2 = Vector2()
var _edited_resource_rect_border_color : Color = Color(1, 1, 1, 1)
var _edited_resource_rect_color : Color = Color(0.8, 0.8, 0.8, 0.9)
var _editor_rect_border_size : int = 2
var _edited_resource_font_color : Color = Color(0, 0, 0, 1)
var _editor_additional_text : String = ""
var drag_type : int
var drag_offset : Vector2
var drag_offset_far : Vector2
var _rect_scale : float = 1
var _edited_resource_event_ignore : bool = false
var _plugin : EditorPlugin = null
var _undo_redo : UndoRedo = null
func set_plugin(plugin : EditorPlugin) -> void:
_plugin = plugin
_undo_redo = _plugin.get_undo_redo()
func _draw():
draw_rect(Rect2(Vector2(), get_size()), _edited_resource_rect_color)
draw_rect(Rect2(Vector2(), get_size()), _edited_resource_rect_border_color, false, _editor_rect_border_size)
var font : Font = get_theme_font("font")
var res_name : String = "NULL"
if edited_resource:
res_name = edited_resource.resource_name
var res_cls : String = ""
if edited_resource:
res_cls = edited_resource.get_editor_class()
draw_string(font, Vector2(_editor_rect_border_size, font.get_height()), res_name, _edited_resource_font_color)
if res_cls != "":
draw_string(font, Vector2(_editor_rect_border_size, font.get_height() * 2), res_cls, _edited_resource_font_color, get_rect().size.x)
if _editor_additional_text != "":
draw_string(font, Vector2(_editor_rect_border_size, font.get_height() * 3), _editor_additional_text, _edited_resource_font_color, get_rect().size.x)
if edited_resource:
edited_resource.eitor_draw_additional(self)
func refresh() -> void:
if !edited_resource:
return
#anchor is bottom left here
var rect : Rect2 = edited_resource.get_rect()
rect.position *= _rect_scale
rect.size *= _rect_scale
#anchor needs to be on top left here
var rp : Vector2 = rect.position
rp.y = edited_resource_parent_size.y * _rect_scale - rect.size.y - rect.position.y
rect_position = rp
rect_size = rect.size
update()
func set_editor_rect_scale(rect_scale) -> void:
_rect_scale = rect_scale
refresh()
func set_edited_resource(res : WorldGenBaseResource):
edited_resource = res
if edited_resource:
_edited_resource_rect_border_color = edited_resource.get_editor_rect_border_color()
_edited_resource_rect_color = edited_resource.get_editor_rect_color()
_editor_rect_border_size = edited_resource.get_editor_rect_border_size()
_edited_resource_font_color = edited_resource.get_editor_font_color()
_editor_additional_text = edited_resource.get_editor_additional_text()
edited_resource.connect("changed", self, "on_edited_resource_changed")
refresh()
func on_edited_resource_changed() -> void:
if _edited_resource_event_ignore:
return
refresh()
#based on / ported from engine/scene/gui/dialogs.h and .cpp
func _notification(p_what : int) -> void:
if (p_what == NOTIFICATION_MOUSE_EXIT):
# Reset the mouse cursor when leaving the resizable window border.
if (edited_resource && !edited_resource.locked && !drag_type):
if (get_default_cursor_shape() != CURSOR_ARROW):
set_default_cursor_shape(CURSOR_ARROW)
#based on / ported from engine/scene/gui/dialogs.h and .cpp
func _gui_input(p_event : InputEvent) -> void:
if (p_event is InputEventMouseButton) && (p_event.get_button_index() == BUTTON_LEFT):
var mb : InputEventMouseButton = p_event as InputEventMouseButton
if (mb.is_pressed()):
# Begin a possible dragging operation.
drag_type = _drag_hit_test(Vector2(mb.get_position().x, mb.get_position().y))
if (drag_type != DragType.DRAG_NONE):
drag_offset = get_global_mouse_position() - get_position()
drag_offset_far = get_position() + get_size() - get_global_mouse_position()
elif (drag_type != DragType.DRAG_NONE && !mb.is_pressed()):
# End a dragging operation.
drag_type = DragType.DRAG_NONE
var rect : Rect2 = get_rect()
#rect needs to be converted back
rect.position.y = edited_resource_parent_size.y * _rect_scale - rect.size.y - rect.position.y
rect.position /= _rect_scale
rect.size /= _rect_scale
#edited_resource.set_rect(rect)
_edited_resource_event_ignore = true
_undo_redo.create_action("WE: Drag End")
_undo_redo.add_do_method(edited_resource, "set_rect", rect)
_undo_redo.add_undo_method(edited_resource, "set_rect", edited_resource.get_rect())
_undo_redo.commit_action()
_edited_resource_event_ignore = false
if p_event is InputEventMouseMotion:
var mm : InputEventMouseMotion = p_event as InputEventMouseMotion
if (drag_type == DragType.DRAG_NONE):
# Update the cursor while moving along the borders.
var cursor = CURSOR_ARROW
if (!edited_resource.locked):
var preview_drag_type : int = _drag_hit_test(Vector2(mm.get_position().x, mm.get_position().y))
var top_left : int = DragType.DRAG_RESIZE_TOP + DragType.DRAG_RESIZE_LEFT
var bottom_right : int = DragType.DRAG_RESIZE_BOTTOM + DragType.DRAG_RESIZE_RIGHT
var top_right : int = DragType.DRAG_RESIZE_TOP + DragType.DRAG_RESIZE_RIGHT
var bottom_left : int = DragType.DRAG_RESIZE_BOTTOM + DragType.DRAG_RESIZE_LEFT
match (preview_drag_type):
DragType.DRAG_RESIZE_TOP:
cursor = CURSOR_VSIZE
DragType.DRAG_RESIZE_BOTTOM:
cursor = CURSOR_VSIZE
DragType.DRAG_RESIZE_LEFT:
cursor = CURSOR_HSIZE
DragType.DRAG_RESIZE_RIGHT:
cursor = CURSOR_HSIZE
top_left:
cursor = CURSOR_FDIAGSIZE
bottom_right:
cursor = CURSOR_FDIAGSIZE
top_right:
cursor = CURSOR_BDIAGSIZE
bottom_left:
cursor = CURSOR_BDIAGSIZE
if (get_cursor_shape() != cursor):
set_default_cursor_shape(cursor);
else:
# Update while in a dragging operation.
var global_pos : Vector2 = get_global_mouse_position()
var rect : Rect2 = get_rect()
var min_size : Vector2 = get_combined_minimum_size()
if (drag_type == DragType.DRAG_MOVE):
rect.position = global_pos - drag_offset
else:
if (drag_type & DragType.DRAG_RESIZE_TOP):
var bottom : int = rect.position.y + rect.size.y
var max_y : int = bottom - min_size.y
rect.position.y = min(global_pos.y - drag_offset.y, max_y)
rect.size.y = bottom - rect.position.y
elif (drag_type & DragType.DRAG_RESIZE_BOTTOM):
rect.size.y = global_pos.y - rect.position.y + drag_offset_far.y
if (drag_type & DragType.DRAG_RESIZE_LEFT):
var right : int = rect.position.x + rect.size.x
var max_x : int = right - min_size.x
rect.position.x = min(global_pos.x - drag_offset.x, max_x)
rect.size.x = right - rect.position.x
elif (drag_type & DragType.DRAG_RESIZE_RIGHT):
rect.size.x = global_pos.x - rect.position.x + drag_offset_far.x
set_size(rect.size)
set_position(rect.position)
#based on / ported from engine/scene/gui/dialogs.h and .cpp
func _drag_hit_test(pos : Vector2) -> int:
var drag_type : int = DragType.DRAG_NONE
if (!edited_resource.locked):
var scaleborder_size : int = 5 #get_constant("scaleborder_size", "WindowDialog")
var rect : Rect2 = get_rect()
if (pos.y < (scaleborder_size)):
drag_type = DragType.DRAG_RESIZE_TOP
elif (pos.y >= (rect.size.y - scaleborder_size)):
drag_type = DragType.DRAG_RESIZE_BOTTOM
if (pos.x < scaleborder_size):
drag_type |= DragType.DRAG_RESIZE_LEFT
elif (pos.x >= (rect.size.x - scaleborder_size)):
drag_type |= DragType.DRAG_RESIZE_RIGHT
if (drag_type == DragType.DRAG_NONE):
drag_type = DragType.DRAG_MOVE
return drag_type

View File

@ -0,0 +1,11 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/world_generator/ui/RectViewNode.gd" type="Script" id=1]
[node name="RectViewNode" type="MarginContainer"]
margin_right = 1024.0
margin_bottom = 600.0
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}

View File

@ -0,0 +1,540 @@
tool
extends ScrollContainer
var EditorResourceWidget : PackedScene = preload("res://addons/world_generator/widgets/EditorResourceWidget.tscn")
var _edited_resource : WorldGenBaseResource = null
var properties : Array = Array()
var _ignore_changed_evend : bool = false
var _refresh_queued : bool = false
var _plugin : EditorPlugin = null
var _undo_redo : UndoRedo = null
func set_plugin(plugin : EditorPlugin) -> void:
_plugin = plugin
_undo_redo = _plugin.get_undo_redo()
func add_h_separator() -> int:
var hsep : HSeparator = HSeparator.new()
var content_node = $MainContainer/Content
content_node.add_child(hsep)
var slot_idx : int = content_node.get_child_count() - 1
return slot_idx
func add_slot_color(getter : String, setter : String) -> int:
var cp : ColorPickerButton = ColorPickerButton.new()
var slot_idx : int = add_slot(getter, setter, cp)
cp.color = _edited_resource.call(getter)
cp.connect("color_changed", _edited_resource, setter)
return slot_idx
func add_slot_label(getter : String, setter : String, slot_name : String) -> int:
var l : Label = Label.new()
l.text = slot_name
return add_slot(getter, setter, l)
func add_slot_resource(getter : String, setter : String, slot_name : String, resource_type : String = "Resource") -> int:
var bc : HBoxContainer = HBoxContainer.new()
bc.set_h_size_flags(SIZE_EXPAND_FILL)
var l : Label = Label.new()
l.text = slot_name
bc.add_child(l)
var r : Control = EditorResourceWidget.instance()
r.set_plugin(_plugin)
r.set_resource_type(resource_type)
r.set_resource(_edited_resource.call(getter))
r.set_h_size_flags(SIZE_EXPAND_FILL)
bc.add_child(r)
var slot_idx : int = add_slot(getter, setter, bc)
r.connect("on_resource_changed", self, "on_widget_resource_changed", [ slot_idx ])
return slot_idx
func add_slot_line_edit(getter : String, setter : String, slot_name : String, placeholder : String = "") -> int:
var bc : HBoxContainer = HBoxContainer.new()
bc.set_h_size_flags(SIZE_EXPAND_FILL)
var l : Label = Label.new()
l.text = slot_name
bc.add_child(l)
var le : LineEdit = LineEdit.new()
le.placeholder_text = placeholder
le.set_h_size_flags(SIZE_EXPAND_FILL)
bc.add_child(le)
var slot_idx : int = add_slot(getter, setter, bc)
le.text = _edited_resource.call(getter)
le.connect("text_entered", self, "on_slot_line_edit_text_entered", [ slot_idx ])
return slot_idx
func add_slot_enum(getter : String, setter : String, slot_name : String, values : Array) -> int:
var bc : VBoxContainer = VBoxContainer.new()
if slot_name:
var l : Label = Label.new()
l.text = slot_name
bc.add_child(l)
var mb : OptionButton = OptionButton.new()
for v in values:
mb.add_item(v)
bc.add_child(mb)
var slot_idx : int = add_slot(getter, setter, bc)
mb.selected = _edited_resource.call(getter)
mb.connect("item_selected", self, "on_slot_enum_item_selected", [ slot_idx ])
return slot_idx
func add_slot_int(getter : String, setter : String, slot_name : String, prange : Vector2 = Vector2(-1000, 1000)) -> int:
var bc : HBoxContainer = HBoxContainer.new()
var l : Label = Label.new()
l.text = slot_name
# l.size_flags_horizontal = SIZE_EXPAND_FILL
bc.add_child(l)
var sb : SpinBox = SpinBox.new()
sb.rounded = true
sb.min_value = prange.x
sb.max_value = prange.y
sb.set_h_size_flags(SIZE_EXPAND_FILL)
bc.add_child(sb)
var slot_idx : int = add_slot(getter, setter, bc)
sb.value = _edited_resource.call(getter)
sb.connect("value_changed", self, "on_int_spinbox_value_changed", [ slot_idx ])
return slot_idx
func add_slot_bool(getter : String, setter : String, slot_name : String) -> int:
var cb : CheckBox = CheckBox.new()
cb.text = slot_name
var slot_idx : int = add_slot(getter, setter, cb)
cb.pressed = _edited_resource.call(getter)
cb.connect("toggled", self, "on_checkbox_value_changed", [ slot_idx ])
return slot_idx
func add_slot_float(getter : String, setter : String, slot_name : String, step : float = 0.1, prange : Vector2 = Vector2(-1000, 1000)) -> int:
var bc : HBoxContainer = HBoxContainer.new()
var l : Label = Label.new()
l.text = slot_name
# l.size_flags_horizontal = SIZE_EXPAND_FILL
bc.add_child(l)
var sb : SpinBox = SpinBox.new()
bc.add_child(sb)
var slot_idx : int = add_slot(getter, setter, bc)
sb.rounded = false
sb.step = step
sb.min_value = prange.x
sb.max_value = prange.y
sb.value = _edited_resource.call(getter)
sb.set_h_size_flags(SIZE_EXPAND_FILL)
sb.connect("value_changed", self, "on_float_spinbox_value_changed", [ slot_idx ])
return slot_idx
func add_slot_vector2(getter : String, setter : String, slot_name : String, step : float = 0.1, prange : Vector2 = Vector2(-1000, 1000)) -> int:
var bc : VBoxContainer = VBoxContainer.new()
var l : Label = Label.new()
l.text = slot_name
bc.add_child(l)
var sbx : SpinBox = SpinBox.new()
bc.add_child(sbx)
var sby : SpinBox = SpinBox.new()
bc.add_child(sby)
var slot_idx : int = add_slot(getter, setter, bc)
sbx.rounded = false
sby.rounded = false
sbx.step = step
sby.step = step
sbx.min_value = prange.x
sbx.max_value = prange.y
sby.min_value = prange.x
sby.max_value = prange.y
var val : Vector2 = _edited_resource.call(getter)
sbx.value = val.x
sby.value = val.y
sbx.connect("value_changed", self, "on_vector2_spinbox_value_changed", [ slot_idx, sbx, sby ])
sby.connect("value_changed", self, "on_vector2_spinbox_value_changed", [ slot_idx, sbx, sby ])
return slot_idx
func add_slot_vector3(getter : String, setter : String, slot_name : String, step : float = 0.1, prange : Vector2 = Vector2(-1000, 1000)) -> int:
var bc : VBoxContainer = VBoxContainer.new()
var l : Label = Label.new()
l.text = slot_name
bc.add_child(l)
var sbx : SpinBox = SpinBox.new()
bc.add_child(sbx)
var sby : SpinBox = SpinBox.new()
bc.add_child(sby)
var sbz : SpinBox = SpinBox.new()
bc.add_child(sbz)
var slot_idx : int = add_slot(getter, setter, bc)
sbx.rounded = false
sby.rounded = false
sbz.rounded = false
sbx.step = step
sby.step = step
sbz.step = step
sbx.min_value = prange.x
sbx.max_value = prange.y
sby.min_value = prange.x
sby.max_value = prange.y
sbz.min_value = prange.x
sbz.max_value = prange.y
var val : Vector3 = _edited_resource.call(getter)
sbx.value = val.x
sby.value = val.y
sbz.value = val.z
sbx.connect("value_changed", self, "on_vector3_spinbox_value_changed", [ slot_idx, sbx, sby, sbz ])
sby.connect("value_changed", self, "on_vector3_spinbox_value_changed", [ slot_idx, sbx, sby, sbz ])
sbz.connect("value_changed", self, "on_vector3_spinbox_value_changed", [ slot_idx, sbx, sby, sbz ])
return slot_idx
func add_slot_rect2(getter : String, setter : String, slot_name : String, step : float = 0.1, prange : Vector2 = Vector2(-10000, 10000)) -> int:
var bc : VBoxContainer = VBoxContainer.new()
bc.size_flags_horizontal = SIZE_EXPAND_FILL
var l : Label = Label.new()
l.text = slot_name
bc.add_child(l)
var hc1 : HBoxContainer = HBoxContainer.new()
hc1.size_flags_horizontal = SIZE_EXPAND_FILL
bc.add_child(hc1)
var sbx : SpinBox = SpinBox.new()
sbx.size_flags_horizontal = SIZE_EXPAND_FILL
hc1.add_child(sbx)
var sby : SpinBox = SpinBox.new()
sby.size_flags_horizontal = SIZE_EXPAND_FILL
hc1.add_child(sby)
var hc2 : HBoxContainer = HBoxContainer.new()
hc2.size_flags_horizontal = SIZE_EXPAND_FILL
bc.add_child(hc2)
var sbw : SpinBox = SpinBox.new()
sbw.size_flags_horizontal = SIZE_EXPAND_FILL
hc2.add_child(sbw)
var sbh : SpinBox = SpinBox.new()
sbh.size_flags_horizontal = SIZE_EXPAND_FILL
hc2.add_child(sbh)
var slot_idx : int = add_slot(getter, setter, bc)
sbx.rounded = false
sby.rounded = false
sbw.rounded = false
sbh.rounded = false
sbx.step = step
sby.step = step
sbw.step = step
sbh.step = step
sbx.min_value = prange.x
sbx.max_value = prange.y
sby.min_value = prange.x
sby.max_value = prange.y
sbw.min_value = prange.x
sbw.max_value = prange.y
sbh.min_value = prange.x
sbh.max_value = prange.y
var val : Rect2 = _edited_resource.call(getter)
sbx.value = val.position.x
sby.value = val.position.y
sbw.value = val.size.x
sbh.value = val.size.y
sbx.connect("value_changed", self, "on_rect2_spinbox_value_changed", [ slot_idx, [ sbx, sby, sbw, sbh ] ])
sby.connect("value_changed", self, "on_rect2_spinbox_value_changed", [ slot_idx, [ sbx, sby, sbw, sbh ] ])
sbw.connect("value_changed", self, "on_rect2_spinbox_value_changed", [ slot_idx, [ sbx, sby, sbw, sbh ] ])
sbh.connect("value_changed", self, "on_rect2_spinbox_value_changed", [ slot_idx, [ sbx, sby, sbw, sbh ] ])
return slot_idx
func add_slot_vector2i(getter : String, setter : String, slot_name : String, step : int = 1, prange : Vector2i = Vector2i(-1000000, 1000000)) -> int:
var bc : VBoxContainer = VBoxContainer.new()
var l : Label = Label.new()
l.text = slot_name
bc.add_child(l)
var sbx : SpinBox = SpinBox.new()
bc.add_child(sbx)
var sby : SpinBox = SpinBox.new()
bc.add_child(sby)
var slot_idx : int = add_slot(getter, setter, bc)
sbx.rounded = true
sby.rounded = true
sbx.step = step
sby.step = step
sbx.min_value = prange.x
sbx.max_value = prange.y
sby.min_value = prange.x
sby.max_value = prange.y
var val : Vector2 = _edited_resource.call(getter)
sbx.value = val.x
sby.value = val.y
sbx.connect("value_changed", self, "on_vector2i_spinbox_value_changed", [ slot_idx, sbx, sby ])
sby.connect("value_changed", self, "on_vector2i_spinbox_value_changed", [ slot_idx, sbx, sby ])
return slot_idx
func add_slot(getter : String, setter : String, control : Control) -> int:
var content_node = $MainContainer/Content
content_node.add_child(control)
var child_idx : int = content_node.get_child_count() - 1
var arr : Array = Array()
arr.append(child_idx)
arr.append(getter)
arr.append(setter)
arr.append(control)
properties.append(arr)
var slot_idx : int = properties.size() - 1
return slot_idx
func get_property_control(slot_idx : int) -> Node:
return properties[slot_idx][3]
func on_int_spinbox_value_changed(val : float, slot_idx) -> void:
_ignore_changed_evend = true
#_edited_resource.call(properties[slot_idx][2], int(val))
_undo_redo.create_action("WE: Set Value")
_undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], int(val))
_undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1]))
_undo_redo.commit_action()
_ignore_changed_evend = false
func on_checkbox_value_changed(val : bool, slot_idx) -> void:
_ignore_changed_evend = true
#_edited_resource.call(properties[slot_idx][2], val)
_undo_redo.create_action("WE: Set Value")
_undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], val)
_undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1]))
_undo_redo.commit_action()
_ignore_changed_evend = false
func on_float_spinbox_value_changed(val : float, slot_idx) -> void:
_ignore_changed_evend = true
#_edited_resource.call(properties[slot_idx][2], val)
_undo_redo.create_action("WE: Set Value")
_undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], val)
_undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1]))
_undo_redo.commit_action()
_ignore_changed_evend = false
func on_vector2_spinbox_value_changed(val : float, slot_idx, spinbox_x, spinbox_y) -> void:
_ignore_changed_evend = true
var vv : Vector2 = Vector2(spinbox_x.value, spinbox_y.value)
#_edited_resource.call(properties[slot_idx][2], vv)
_undo_redo.create_action("WE: Set Value")
_undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], vv)
_undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1]))
_undo_redo.commit_action()
_ignore_changed_evend = false
func on_vector3_spinbox_value_changed(val : float, slot_idx, spinbox_x, spinbox_y, spinbox_z) -> void:
_ignore_changed_evend = true
var vv : Vector3 = Vector3(spinbox_x.value, spinbox_y.value, spinbox_z.value)
#_edited_resource.call(properties[slot_idx][2], vv)
_undo_redo.create_action("WE: Set Value")
_undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], vv)
_undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1]))
_undo_redo.commit_action()
_ignore_changed_evend = false
func on_rect2_spinbox_value_changed(val : float, slot_idx, spinboxes) -> void:
_ignore_changed_evend = true
var vv : Rect2 = Rect2(spinboxes[0].value, spinboxes[1].value, spinboxes[2].value, spinboxes[3].value)
#_edited_resource.call(properties[slot_idx][2], vv)
_undo_redo.create_action("WE: Set Value")
_undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], vv)
_undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1]))
_undo_redo.commit_action()
_ignore_changed_evend = false
func on_vector2i_spinbox_value_changed(val : float, slot_idx, spinbox_x, spinbox_y) -> void:
_ignore_changed_evend = true
var vv : Vector2i = Vector2i(spinbox_x.value, spinbox_y.value)
#_edited_resource.call(properties[slot_idx][2], vv)
_undo_redo.create_action("WE: Set Value")
_undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], vv)
_undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1]))
_undo_redo.commit_action()
_ignore_changed_evend = false
func on_slot_enum_item_selected(val : int, slot_idx : int) -> void:
_ignore_changed_evend = true
#_edited_resource.call(properties[slot_idx][2], val)
_undo_redo.create_action("WE: Set Value")
_undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], val)
_undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1]))
_undo_redo.commit_action()
_ignore_changed_evend = false
func on_slot_line_edit_text_entered(text : String, slot_idx : int) -> void:
_ignore_changed_evend = true
#_edited_resource.call(properties[slot_idx][2], text)
_undo_redo.create_action("WE: Set Value")
_undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], text)
_undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1]))
_undo_redo.commit_action()
_ignore_changed_evend = false
func on_widget_resource_changed(res : Resource, slot_idx : int) -> void:
_ignore_changed_evend = true
#_edited_resource.call(properties[slot_idx][2], res)
_undo_redo.create_action("WE: Set Value")
_undo_redo.add_do_method(_edited_resource, properties[slot_idx][2], res)
_undo_redo.add_undo_method(_edited_resource, properties[slot_idx][2], _edited_resource.call(properties[slot_idx][1]))
_undo_redo.commit_action()
_ignore_changed_evend = false
func clear() -> void:
properties.clear()
var content_node = $MainContainer/Content
if !content_node:
return
for c in content_node.get_children():
c.queue_free()
content_node.remove_child(c)
func refresh() -> void:
clear()
var cls_str : String = "[none]"
var script_str : String = "[none]"
if _edited_resource:
cls_str = _edited_resource.get_class()
var scr = _edited_resource.get_script()
if scr:
script_str = scr.resource_path
_edited_resource.setup_property_inspector(self)
$MainContainer/HBoxContainer/ClassLE.text = cls_str
$MainContainer/HBoxContainer2/ScriptLE.text = script_str
_refresh_queued = false
func edit_resource(wgw) -> void:
if _edited_resource:
_edited_resource.disconnect("changed", self, "on_edited_resource_changed")
_edited_resource = wgw
#if !_edited_resource.is_connected("changed", self, "on_edited_resource_changed"):
if _edited_resource:
_edited_resource.connect("changed", self, "on_edited_resource_changed")
refresh()
func on_edited_resource_changed() -> void:
if _ignore_changed_evend:
return
if _refresh_queued:
return
_refresh_queued = true
call_deferred("refresh")

View File

@ -0,0 +1,81 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/world_generator/ui/ResourcePropertyList.gd" type="Script" id=1]
[node name="ResourcePropertyList" type="ScrollContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
rect_min_size = Vector2( 100, 0 )
scroll_horizontal_enabled = false
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="MainContainer" type="VBoxContainer" parent="."]
margin_right = 1024.0
margin_bottom = 90.0
size_flags_horizontal = 3
[node name="Label" type="Label" parent="MainContainer"]
margin_right = 1024.0
margin_bottom = 14.0
text = "Properties"
align = 1
valign = 1
[node name="HSeparator" type="HSeparator" parent="MainContainer"]
margin_top = 18.0
margin_right = 1024.0
margin_bottom = 22.0
[node name="Content" type="VBoxContainer" parent="MainContainer"]
margin_top = 26.0
margin_right = 1024.0
margin_bottom = 26.0
size_flags_horizontal = 3
[node name="HSeparator2" type="HSeparator" parent="MainContainer"]
margin_top = 30.0
margin_right = 1024.0
margin_bottom = 34.0
[node name="HBoxContainer" type="HBoxContainer" parent="MainContainer"]
margin_top = 38.0
margin_right = 1024.0
margin_bottom = 62.0
size_flags_horizontal = 3
[node name="Label" type="Label" parent="MainContainer/HBoxContainer"]
margin_top = 5.0
margin_right = 37.0
margin_bottom = 19.0
text = "Class "
valign = 1
[node name="ClassLE" type="LineEdit" parent="MainContainer/HBoxContainer"]
margin_left = 41.0
margin_right = 1024.0
margin_bottom = 24.0
size_flags_horizontal = 3
editable = false
[node name="HBoxContainer2" type="HBoxContainer" parent="MainContainer"]
margin_top = 66.0
margin_right = 1024.0
margin_bottom = 90.0
size_flags_horizontal = 3
[node name="Label" type="Label" parent="MainContainer/HBoxContainer2"]
margin_top = 5.0
margin_right = 36.0
margin_bottom = 19.0
text = "Script"
valign = 1
[node name="ScriptLE" type="LineEdit" parent="MainContainer/HBoxContainer2"]
margin_left = 40.0
margin_right = 1024.0
margin_bottom = 24.0
size_flags_horizontal = 3
editable = false

View File

@ -0,0 +1,29 @@
tool
extends HBoxContainer
var edited_world
signal request_item_edit(world_gen_base_resource)
func _ready():
var dl : Control = get_node("VBoxContainer/DataList")
if !dl.is_connected("request_item_edit", self, "on_request_item_edit"):
dl.connect("request_item_edit", self, "on_request_item_edit")
func set_plugin(plugin : EditorPlugin) -> void:
$HSplitContainer/ResourcePropertyList.set_plugin(plugin)
$HSplitContainer/RectEditor.set_plugin(plugin)
$VBoxContainer/DataList.set_plugin(plugin)
func refresh() -> void:
$HSplitContainer/ResourcePropertyList.edit_resource(edited_world)
$VBoxContainer/DataList.set_edited_resource(edited_world)
$HSplitContainer/RectEditor.set_edited_resource(edited_world)
func set_wgworld(wgw : WorldGenWorld) -> void:
edited_world = wgw
refresh()
func on_request_item_edit(resource : WorldGenBaseResource) -> void:
emit_signal("request_item_edit", resource)

View File

@ -0,0 +1,78 @@
tool
extends HBoxContainer
var edited_world : WorldGenWorld = null
var edited_continent : Continent = null
signal request_item_edit(continent, world_gen_base_resource)
func _ready():
var option_button : OptionButton = $HSplitContainer/VBoxContainer/OptionButton
option_button.connect("item_selected", self, "on_item_selected")
var dl : Control = get_node("HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList")
if !dl.is_connected("request_item_edit", self, "on_request_item_edit"):
dl.connect("request_item_edit", self, "on_request_item_edit")
func set_plugin(plugin : EditorPlugin) -> void:
$HSplitContainer/VBoxContainer/HBoxContainer2/ResourcePropertyList.set_plugin(plugin)
$HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList.set_plugin(plugin)
$HSplitContainer/RectEditor.set_plugin(plugin)
func refresh_continent() -> void:
$HSplitContainer/VBoxContainer/HBoxContainer2/ResourcePropertyList.edit_resource(edited_continent)
$HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList.set_edited_resource(edited_continent)
$HSplitContainer/RectEditor.set_edited_resource(edited_continent)
# if !edited_continent:
# return
func refresh() -> void:
var option_button : OptionButton = $HSplitContainer/VBoxContainer/OptionButton
option_button.clear()
if !edited_world:
return
var content : Array = edited_world.get_content()
for c in content:
if c:
option_button.add_item(c.resource_name)
option_button.set_item_metadata(option_button.get_item_count() - 1, c)
if !edited_continent:
edited_continent = c
refresh_continent()
func set_wgworld(wgw : WorldGenWorld) -> void:
edited_world = wgw
refresh()
func switch_to(resource : WorldGenBaseResource) -> void:
var option_button : OptionButton = $HSplitContainer/VBoxContainer/OptionButton
for i in range(option_button.get_item_count()):
var continent : Continent = option_button.get_item_metadata(i)
if (continent == resource):
option_button.select(i)
set_continent(continent)
return
func set_continent(continent : Continent) -> void:
edited_continent = continent
refresh_continent()
func on_item_selected(idx : int) -> void:
var option_button : OptionButton = $HSplitContainer/VBoxContainer/OptionButton
set_continent(option_button.get_item_metadata(idx))
func on_request_item_edit(resource : WorldGenBaseResource) -> void:
emit_signal("request_item_edit", edited_continent, resource)

View File

@ -0,0 +1,100 @@
[gd_scene load_steps=5 format=2]
[ext_resource path="res://addons/world_generator/ui/tabs/Continent.gd" type="Script" id=1]
[ext_resource path="res://addons/world_generator/ui/ResourcePropertyList.tscn" type="PackedScene" id=2]
[ext_resource path="res://addons/world_generator/ui/DataList.tscn" type="PackedScene" id=3]
[ext_resource path="res://addons/world_generator/ui/RectEditor.tscn" type="PackedScene" id=4]
[node name="Continent" type="HBoxContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="HSplitContainer" type="HSplitContainer" parent="."]
margin_right = 1024.0
margin_bottom = 600.0
size_flags_horizontal = 3
[node name="RectEditor" parent="HSplitContainer" instance=ExtResource( 4 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 735.0
margin_bottom = 600.0
size_flags_horizontal = 3
[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer"]
margin_left = 747.0
margin_right = 1024.0
margin_bottom = 600.0
[node name="OptionButton" type="OptionButton" parent="HSplitContainer/VBoxContainer"]
margin_right = 277.0
margin_bottom = 20.0
[node name="HBoxContainer2" type="HBoxContainer" parent="HSplitContainer/VBoxContainer"]
margin_top = 24.0
margin_right = 277.0
margin_bottom = 600.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="ResourcePropertyList" parent="HSplitContainer/VBoxContainer/HBoxContainer2" instance=ExtResource( 2 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 100.0
margin_bottom = 576.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer/VBoxContainer/HBoxContainer2"]
margin_left = 104.0
margin_right = 277.0
margin_bottom = 576.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Label" type="Label" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer"]
margin_right = 173.0
margin_bottom = 14.0
text = "Zones"
align = 1
valign = 1
[node name="HBoxContainer" type="HBoxContainer" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer"]
margin_top = 18.0
margin_right = 173.0
margin_bottom = 38.0
[node name="AddButton" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"]
margin_right = 37.0
margin_bottom = 20.0
text = "Add"
[node name="DeleteButton" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"]
margin_left = 41.0
margin_right = 96.0
margin_bottom = 20.0
text = "Delete"
[node name="Duplicate" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"]
margin_left = 100.0
margin_right = 173.0
margin_bottom = 20.0
text = "Duplicate"
[node name="DataList" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer" instance=ExtResource( 3 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 42.0
margin_right = 173.0
margin_bottom = 576.0
class_types = 1
[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/AddButton" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="add_button_pressed"]
[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/DeleteButton" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="delete_button_pressed"]
[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/Duplicate" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="duplicate_button_pressed"]

View File

@ -0,0 +1,168 @@
tool
extends HBoxContainer
var edited_world : WorldGenWorld = null
var edited_continent : Continent = null
var edited_zone : Zone = null
var edited_sub_zone : SubZone = null
signal request_item_edit(continent, zone, subzone, subzone_prop)
func _ready():
var coption_button : OptionButton = $HSplitContainer/VBoxContainer/ContinentOptionButton
coption_button.connect("item_selected", self, "on_continent_item_selected")
var zoption_button : OptionButton = $HSplitContainer/VBoxContainer/ZoneOptionButton
zoption_button.connect("item_selected", self, "on_zone_item_selected")
var szoption_button : OptionButton = $HSplitContainer/VBoxContainer/SubZoneOptionButton
szoption_button.connect("item_selected", self, "on_sub_zone_item_selected")
var dl : Control = get_node("HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList")
if !dl.is_connected("request_item_edit", self, "on_request_item_edit"):
dl.connect("request_item_edit", self, "on_request_item_edit")
func set_plugin(plugin : EditorPlugin) -> void:
$HSplitContainer/VBoxContainer/HBoxContainer2/ResourcePropertyList.set_plugin(plugin)
$HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList.set_plugin(plugin)
$HSplitContainer/RectEditor.set_plugin(plugin)
func refresh() -> void:
var option_button : OptionButton = $HSplitContainer/VBoxContainer/ContinentOptionButton
option_button.clear()
edited_continent = null
edited_zone = null
if !edited_world:
return
var content : Array = edited_world.get_content()
for c in content:
if c:
option_button.add_item(c.resource_name)
option_button.set_item_metadata(option_button.get_item_count() - 1, c)
if !edited_continent:
edited_continent = c
continent_changed()
func continent_changed() -> void:
var option_button : OptionButton = $HSplitContainer/VBoxContainer/ZoneOptionButton
option_button.clear()
edited_zone = null
if !edited_continent:
return
var content : Array = edited_continent.get_content()
for c in content:
if c:
option_button.add_item(c.resource_name)
option_button.set_item_metadata(option_button.get_item_count() - 1, c)
if !edited_zone:
edited_zone = c
zone_changed()
func zone_changed() -> void:
var option_button : OptionButton = $HSplitContainer/VBoxContainer/SubZoneOptionButton
option_button.clear()
edited_sub_zone = null
if !edited_zone:
return
var content : Array = edited_zone.get_content()
for c in content:
if c:
option_button.add_item(c.resource_name)
option_button.set_item_metadata(option_button.get_item_count() - 1, c)
if !edited_sub_zone:
edited_sub_zone = c
sub_zone_changed()
func sub_zone_changed() -> void:
$HSplitContainer/VBoxContainer/HBoxContainer2/ResourcePropertyList.edit_resource(edited_sub_zone)
$HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList.set_edited_resource(edited_sub_zone)
$HSplitContainer/RectEditor.set_edited_resource(edited_sub_zone)
func set_continent(continent : Continent) -> void:
edited_continent = continent
edited_zone = null
continent_changed()
func set_zone(zone : Zone) -> void:
edited_zone = zone
zone_changed()
func set_sub_zone(sub_zone : SubZone) -> void:
edited_sub_zone = sub_zone
sub_zone_changed()
func set_wgworld(wgw : WorldGenWorld) -> void:
edited_world = wgw
edited_continent = null
edited_zone = null
refresh()
func switch_to(continent : WorldGenBaseResource, zone : WorldGenBaseResource, subzone : WorldGenBaseResource) -> void:
var contob : OptionButton = $HSplitContainer/VBoxContainer/ContinentOptionButton
for i in range(contob.get_item_count()):
var ccont : Continent = contob.get_item_metadata(i)
if (ccont == continent):
contob.select(i)
set_continent(continent)
break
var zoneob : OptionButton = $HSplitContainer/VBoxContainer/ZoneOptionButton
for i in range(zoneob.get_item_count()):
var czone : Zone = zoneob.get_item_metadata(i)
if (czone == zone):
zoneob.select(i)
set_zone(zone)
break
var subzoneob : OptionButton = $HSplitContainer/VBoxContainer/SubZoneOptionButton
for i in range(subzoneob.get_item_count()):
var cszone : SubZone = subzoneob.get_item_metadata(i)
if (cszone == subzone):
subzoneob.select(i)
set_sub_zone(subzone)
return
func on_continent_item_selected(idx : int) -> void:
var option_button : OptionButton = $HSplitContainer/VBoxContainer/ContinentOptionButton
set_continent(option_button.get_item_metadata(idx))
func on_zone_item_selected(idx : int) -> void:
var option_button : OptionButton = $HSplitContainer/VBoxContainer/ZoneOptionButton
set_zone(option_button.get_item_metadata(idx))
func on_sub_zone_item_selected(idx : int) -> void:
var option_button : OptionButton = $HSplitContainer/VBoxContainer/SubZoneOptionButton
set_sub_zone(option_button.get_item_metadata(idx))
func on_request_item_edit(resource : WorldGenBaseResource) -> void:
emit_signal("request_item_edit", edited_continent, edited_zone, edited_sub_zone, resource)

View File

@ -0,0 +1,107 @@
[gd_scene load_steps=5 format=2]
[ext_resource path="res://addons/world_generator/ui/tabs/SubZone.gd" type="Script" id=1]
[ext_resource path="res://addons/world_generator/ui/ResourcePropertyList.tscn" type="PackedScene" id=2]
[ext_resource path="res://addons/world_generator/ui/DataList.tscn" type="PackedScene" id=3]
[ext_resource path="res://addons/world_generator/ui/RectEditor.tscn" type="PackedScene" id=4]
[node name="SubZone" type="HBoxContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource( 1 )
[node name="HSplitContainer" type="HSplitContainer" parent="."]
margin_right = 1024.0
margin_bottom = 600.0
size_flags_horizontal = 3
[node name="RectEditor" parent="HSplitContainer" instance=ExtResource( 4 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 735.0
margin_bottom = 600.0
size_flags_horizontal = 3
[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer"]
margin_left = 747.0
margin_right = 1024.0
margin_bottom = 600.0
[node name="ContinentOptionButton" type="OptionButton" parent="HSplitContainer/VBoxContainer"]
margin_right = 277.0
margin_bottom = 20.0
[node name="ZoneOptionButton" type="OptionButton" parent="HSplitContainer/VBoxContainer"]
margin_top = 24.0
margin_right = 277.0
margin_bottom = 44.0
[node name="SubZoneOptionButton" type="OptionButton" parent="HSplitContainer/VBoxContainer"]
margin_top = 48.0
margin_right = 277.0
margin_bottom = 68.0
[node name="HBoxContainer2" type="HBoxContainer" parent="HSplitContainer/VBoxContainer"]
margin_top = 72.0
margin_right = 277.0
margin_bottom = 600.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="ResourcePropertyList" parent="HSplitContainer/VBoxContainer/HBoxContainer2" instance=ExtResource( 2 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 100.0
margin_bottom = 528.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer/VBoxContainer/HBoxContainer2"]
margin_left = 104.0
margin_right = 277.0
margin_bottom = 528.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Label" type="Label" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer"]
margin_right = 173.0
margin_bottom = 14.0
text = "Sub Zones"
align = 1
valign = 1
[node name="HBoxContainer" type="HBoxContainer" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer"]
margin_top = 18.0
margin_right = 173.0
margin_bottom = 38.0
[node name="AddButton" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"]
margin_right = 37.0
margin_bottom = 20.0
text = "Add"
[node name="DeleteButton" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"]
margin_left = 41.0
margin_right = 96.0
margin_bottom = 20.0
text = "Delete"
[node name="Duplicate" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"]
margin_left = 100.0
margin_right = 173.0
margin_bottom = 20.0
text = "Duplicate"
[node name="DataList" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer" instance=ExtResource( 3 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 42.0
margin_right = 173.0
margin_bottom = 528.0
class_types = 3
[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/AddButton" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="add_button_pressed"]
[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/DeleteButton" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="delete_button_pressed"]
[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/Duplicate" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="duplicate_button_pressed"]

View File

@ -0,0 +1,204 @@
tool
extends HBoxContainer
var edited_world : WorldGenWorld = null
var edited_continent : Continent = null
var edited_zone : Zone = null
var edited_sub_zone : SubZone = null
var edited_sub_zone_prop : SubZoneProp = null
func _ready():
var coption_button : OptionButton = $VBoxContainer/ContinentOptionButton
coption_button.connect("item_selected", self, "on_continent_item_selected")
var zoption_button : OptionButton = $VBoxContainer/ZoneOptionButton
zoption_button.connect("item_selected", self, "on_zone_item_selected")
var szoption_button : OptionButton = $VBoxContainer/SubZoneOptionButton
szoption_button.connect("item_selected", self, "on_sub_zone_item_selected")
var szpoption_button : OptionButton = $VBoxContainer/SubZonePropOptionButton
szpoption_button.connect("item_selected", self, "on_sub_zone_prop_item_selected")
func set_plugin(plugin : EditorPlugin) -> void:
$VBoxContainer/HBoxContainer2/ResourcePropertyList.set_plugin(plugin)
func continent_changed() -> void:
var option_button : OptionButton = $VBoxContainer/ZoneOptionButton
option_button.clear()
edited_zone = null
edited_sub_zone = null
if !edited_continent:
return
var content : Array = edited_continent.get_content()
for c in content:
if c:
option_button.add_item(c.resource_name)
option_button.set_item_metadata(option_button.get_item_count() - 1, c)
if !edited_zone:
edited_zone = c
zone_changed()
func zone_changed() -> void:
var option_button : OptionButton = $VBoxContainer/SubZoneOptionButton
option_button.clear()
edited_sub_zone = null
if !edited_zone:
return
var content : Array = edited_zone.get_content()
for c in content:
if c:
option_button.add_item(c.resource_name)
option_button.set_item_metadata(option_button.get_item_count() - 1, c)
if !edited_sub_zone:
edited_sub_zone = c
sub_zone_changed()
func sub_zone_changed() -> void:
var option_button : OptionButton = $VBoxContainer/SubZonePropOptionButton
option_button.clear()
edited_sub_zone_prop = null
if !edited_sub_zone:
return
var content : Array = edited_sub_zone.get_content()
for c in content:
if c:
option_button.add_item(c.resource_name)
option_button.set_item_metadata(option_button.get_item_count() - 1, c)
if !edited_sub_zone_prop:
edited_sub_zone_prop = c
sub_zone_prop_changed()
func sub_zone_prop_changed() -> void:
$VBoxContainer/HBoxContainer2/ResourcePropertyList.edit_resource(edited_sub_zone_prop)
func refresh() -> void:
var option_button : OptionButton = $VBoxContainer/ContinentOptionButton
option_button.clear()
if !edited_world:
return
var content : Array = edited_world.get_content()
for c in content:
if c:
option_button.add_item(c.resource_name)
option_button.set_item_metadata(option_button.get_item_count() - 1, c)
if !edited_continent:
edited_continent = c
continent_changed()
func set_wgworld(wgw : WorldGenWorld) -> void:
edited_world = wgw
edited_continent = null
edited_zone = null
edited_sub_zone = null
edited_sub_zone_prop = null
refresh()
func set_continent(continent : Continent) -> void:
edited_continent = continent
edited_zone = null
edited_sub_zone = null
edited_sub_zone_prop = null
continent_changed()
func set_zone(zone : Zone) -> void:
edited_zone = zone
edited_sub_zone = null
edited_sub_zone_prop = null
zone_changed()
func set_sub_zone(sub_zone : SubZone) -> void:
edited_sub_zone = sub_zone
edited_sub_zone_prop = null
sub_zone_changed()
func set_sub_zone_prop(sub_zone_prop : SubZoneProp) -> void:
edited_sub_zone_prop = sub_zone_prop
sub_zone_prop_changed()
func switch_to(continent : WorldGenBaseResource, zone : WorldGenBaseResource, subzone : WorldGenBaseResource, subzone_prop : WorldGenBaseResource) -> void:
var contob : OptionButton = $VBoxContainer/ContinentOptionButton
for i in range(contob.get_item_count()):
var ccont : Continent = contob.get_item_metadata(i)
if (ccont == continent):
contob.select(i)
set_continent(continent)
break
var zoneob : OptionButton = $VBoxContainer/ZoneOptionButton
for i in range(zoneob.get_item_count()):
var czone : Zone = zoneob.get_item_metadata(i)
if (czone == zone):
zoneob.select(i)
set_zone(zone)
break
var subzoneob : OptionButton = $VBoxContainer/SubZoneOptionButton
for i in range(subzoneob.get_item_count()):
var cszone : SubZone = subzoneob.get_item_metadata(i)
if (cszone == subzone):
subzoneob.select(i)
set_sub_zone(subzone)
break
var subzonepropob : OptionButton = $VBoxContainer/SubZonePropOptionButton
for i in range(subzonepropob.get_item_count()):
var cszoneprop : SubZoneProp = subzonepropob.get_item_metadata(i)
if (cszoneprop == subzone_prop):
subzonepropob.select(i)
set_sub_zone_prop(subzone_prop)
return
func on_continent_item_selected(idx : int) -> void:
var option_button : OptionButton = $VBoxContainer/ContinentOptionButton
set_continent(option_button.get_item_metadata(idx))
func on_zone_item_selected(idx : int) -> void:
var option_button : OptionButton = $VBoxContainer/ZoneOptionButton
set_zone(option_button.get_item_metadata(idx))
func on_sub_zone_item_selected(idx : int) -> void:
var option_button : OptionButton = $VBoxContainer/SubZoneOptionButton
set_sub_zone(option_button.get_item_metadata(idx))
func on_sub_zone_prop_item_selected(idx : int) -> void:
var option_button : OptionButton = $VBoxContainer/SubZonePropOptionButton
set_sub_zone_prop(option_button.get_item_metadata(idx))

View File

@ -0,0 +1,51 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://addons/world_generator/ui/tabs/SubZoneProp.gd" type="Script" id=1]
[ext_resource path="res://addons/world_generator/ui/ResourcePropertyList.tscn" type="PackedScene" id=2]
[node name="SubZoneProp" type="HBoxContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource( 1 )
[node name="VBoxContainer" type="VBoxContainer" parent="."]
margin_right = 1024.0
margin_bottom = 600.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="ContinentOptionButton" type="OptionButton" parent="VBoxContainer"]
margin_right = 1024.0
margin_bottom = 20.0
[node name="ZoneOptionButton" type="OptionButton" parent="VBoxContainer"]
margin_top = 24.0
margin_right = 1024.0
margin_bottom = 44.0
[node name="SubZoneOptionButton" type="OptionButton" parent="VBoxContainer"]
margin_top = 48.0
margin_right = 1024.0
margin_bottom = 68.0
[node name="SubZonePropOptionButton" type="OptionButton" parent="VBoxContainer"]
margin_top = 72.0
margin_right = 1024.0
margin_bottom = 92.0
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer"]
margin_top = 96.0
margin_right = 1024.0
margin_bottom = 600.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="ResourcePropertyList" parent="VBoxContainer/HBoxContainer2" instance=ExtResource( 2 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 1024.0
margin_bottom = 504.0
size_flags_horizontal = 3
size_flags_vertical = 3

View File

@ -0,0 +1,79 @@
[gd_scene load_steps=5 format=2]
[ext_resource path="res://addons/world_generator/ui/ResourcePropertyList.tscn" type="PackedScene" id=2]
[ext_resource path="res://addons/world_generator/ui/WorldTab.gd" type="Script" id=5]
[ext_resource path="res://addons/world_generator/ui/DataList.tscn" type="PackedScene" id=6]
[ext_resource path="res://addons/world_generator/ui/RectEditor.tscn" type="PackedScene" id=7]
[node name="World" type="HBoxContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 4.0
margin_top = 32.0
margin_right = -4.0
margin_bottom = -4.0
script = ExtResource( 5 )
[node name="HSplitContainer" type="HSplitContainer" parent="."]
margin_right = 839.0
margin_bottom = 564.0
size_flags_horizontal = 3
[node name="RectEditor" parent="HSplitContainer" instance=ExtResource( 7 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 727.0
margin_bottom = 564.0
size_flags_horizontal = 3
[node name="ResourcePropertyList" parent="HSplitContainer" instance=ExtResource( 2 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 739.0
margin_right = 839.0
margin_bottom = 564.0
[node name="VBoxContainer" type="VBoxContainer" parent="."]
margin_left = 843.0
margin_right = 1016.0
margin_bottom = 564.0
[node name="Label" type="Label" parent="VBoxContainer"]
margin_right = 173.0
margin_bottom = 14.0
text = "Continents"
align = 1
valign = 1
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
margin_top = 18.0
margin_right = 173.0
margin_bottom = 38.0
[node name="AddButton" type="Button" parent="VBoxContainer/HBoxContainer"]
margin_right = 37.0
margin_bottom = 20.0
text = "Add"
[node name="DeleteButton" type="Button" parent="VBoxContainer/HBoxContainer"]
margin_left = 41.0
margin_right = 96.0
margin_bottom = 20.0
text = "Delete"
[node name="Duplicate" type="Button" parent="VBoxContainer/HBoxContainer"]
margin_left = 100.0
margin_right = 173.0
margin_bottom = 20.0
text = "Duplicate"
[node name="DataList" parent="VBoxContainer" instance=ExtResource( 6 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 42.0
margin_right = 173.0
margin_bottom = 564.0
[connection signal="pressed" from="VBoxContainer/HBoxContainer/AddButton" to="VBoxContainer/DataList" method="add_button_pressed"]
[connection signal="pressed" from="VBoxContainer/HBoxContainer/DeleteButton" to="VBoxContainer/DataList" method="delete_button_pressed"]
[connection signal="pressed" from="VBoxContainer/HBoxContainer/Duplicate" to="VBoxContainer/DataList" method="duplicate_button_pressed"]

View File

@ -0,0 +1,122 @@
tool
extends HBoxContainer
var edited_world : WorldGenWorld = null
var edited_continent : Continent = null
var edited_zone : Zone = null
signal request_item_edit(continent, zone, subzone)
func _ready():
var coption_button : OptionButton = $HSplitContainer/VBoxContainer/ContinentOptionButton
coption_button.connect("item_selected", self, "on_continent_item_selected")
var zoption_button : OptionButton = $HSplitContainer/VBoxContainer/ZoneOptionButton
zoption_button.connect("item_selected", self, "on_zone_item_selected")
var dl : Control = get_node("HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList")
if !dl.is_connected("request_item_edit", self, "on_request_item_edit"):
dl.connect("request_item_edit", self, "on_request_item_edit")
func set_plugin(plugin : EditorPlugin) -> void:
$HSplitContainer/VBoxContainer/HBoxContainer2/ResourcePropertyList.set_plugin(plugin)
$HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList.set_plugin(plugin)
$HSplitContainer/RectEditor.set_plugin(plugin)
func refresh() -> void:
var option_button : OptionButton = $HSplitContainer/VBoxContainer/ContinentOptionButton
option_button.clear()
edited_continent = null
edited_zone = null
if !edited_world:
return
var content : Array = edited_world.get_content()
for c in content:
if c:
option_button.add_item(c.resource_name)
option_button.set_item_metadata(option_button.get_item_count() - 1, c)
if !edited_continent:
edited_continent = c
continent_changed()
func continent_changed() -> void:
var option_button : OptionButton = $HSplitContainer/VBoxContainer/ZoneOptionButton
option_button.clear()
edited_zone = null
if !edited_continent:
return
var content : Array = edited_continent.get_content()
for c in content:
if c:
option_button.add_item(c.resource_name)
option_button.set_item_metadata(option_button.get_item_count() - 1, c)
if !edited_zone:
edited_zone = c
zone_changed()
func zone_changed() -> void:
$HSplitContainer/VBoxContainer/HBoxContainer2/ResourcePropertyList.edit_resource(edited_zone)
$HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList.set_edited_resource(edited_zone)
$HSplitContainer/RectEditor.set_edited_resource(edited_zone)
func set_continent(continent : Continent) -> void:
edited_continent = continent
edited_zone = null
continent_changed()
func set_zone(zone : Zone) -> void:
edited_zone = zone
zone_changed()
func set_wgworld(wgw : WorldGenWorld) -> void:
edited_world = wgw
edited_continent = null
edited_zone = null
refresh()
func switch_to(continent : WorldGenBaseResource, resource : WorldGenBaseResource) -> void:
var contob : OptionButton = $HSplitContainer/VBoxContainer/ContinentOptionButton
for i in range(contob.get_item_count()):
var ccont : Continent = contob.get_item_metadata(i)
if (ccont == continent):
contob.select(i)
set_continent(continent)
break
var zoneob : OptionButton = $HSplitContainer/VBoxContainer/ZoneOptionButton
for i in range(zoneob.get_item_count()):
var czone : Zone = zoneob.get_item_metadata(i)
if (czone == resource):
zoneob.select(i)
set_zone(czone)
return
func on_continent_item_selected(idx : int) -> void:
var option_button : OptionButton = $HSplitContainer/VBoxContainer/ContinentOptionButton
set_continent(option_button.get_item_metadata(idx))
func on_zone_item_selected(idx : int) -> void:
var option_button : OptionButton = $HSplitContainer/VBoxContainer/ZoneOptionButton
set_zone(option_button.get_item_metadata(idx))
func on_request_item_edit(resource : WorldGenBaseResource) -> void:
emit_signal("request_item_edit", edited_continent, edited_zone, resource)

View File

@ -0,0 +1,105 @@
[gd_scene load_steps=5 format=2]
[ext_resource path="res://addons/world_generator/ui/tabs/Zone.gd" type="Script" id=1]
[ext_resource path="res://addons/world_generator/ui/ResourcePropertyList.tscn" type="PackedScene" id=2]
[ext_resource path="res://addons/world_generator/ui/DataList.tscn" type="PackedScene" id=3]
[ext_resource path="res://addons/world_generator/ui/RectEditor.tscn" type="PackedScene" id=4]
[node name="Zone" type="HBoxContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="HSplitContainer" type="HSplitContainer" parent="."]
margin_right = 1024.0
margin_bottom = 600.0
size_flags_horizontal = 3
[node name="RectEditor" parent="HSplitContainer" instance=ExtResource( 4 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 735.0
margin_bottom = 600.0
size_flags_horizontal = 3
[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer"]
margin_left = 747.0
margin_right = 1024.0
margin_bottom = 600.0
[node name="ContinentOptionButton" type="OptionButton" parent="HSplitContainer/VBoxContainer"]
margin_right = 277.0
margin_bottom = 20.0
[node name="ZoneOptionButton" type="OptionButton" parent="HSplitContainer/VBoxContainer"]
margin_top = 24.0
margin_right = 277.0
margin_bottom = 44.0
[node name="HBoxContainer2" type="HBoxContainer" parent="HSplitContainer/VBoxContainer"]
margin_top = 48.0
margin_right = 277.0
margin_bottom = 600.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="ResourcePropertyList" parent="HSplitContainer/VBoxContainer/HBoxContainer2" instance=ExtResource( 2 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 100.0
margin_bottom = 552.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer/VBoxContainer/HBoxContainer2"]
margin_left = 104.0
margin_right = 277.0
margin_bottom = 552.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Label" type="Label" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer"]
margin_right = 173.0
margin_bottom = 14.0
text = "Sub Zones"
align = 1
valign = 1
[node name="HBoxContainer" type="HBoxContainer" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer"]
margin_top = 18.0
margin_right = 173.0
margin_bottom = 38.0
[node name="AddButton" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"]
margin_right = 37.0
margin_bottom = 20.0
text = "Add"
[node name="DeleteButton" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"]
margin_left = 41.0
margin_right = 96.0
margin_bottom = 20.0
text = "Delete"
[node name="Duplicate" type="Button" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer"]
margin_left = 100.0
margin_right = 173.0
margin_bottom = 20.0
text = "Duplicate"
[node name="DataList" parent="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer" instance=ExtResource( 3 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_top = 42.0
margin_right = 173.0
margin_bottom = 552.0
class_types = 2
[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/AddButton" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="add_button_pressed"]
[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/DeleteButton" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="delete_button_pressed"]
[connection signal="pressed" from="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/HBoxContainer/Duplicate" to="HSplitContainer/VBoxContainer/HBoxContainer2/VBoxContainer/DataList" method="duplicate_button_pressed"]

View File

@ -0,0 +1,80 @@
tool
extends HBoxContainer
var _resource_type : String = "Resource"
var _resource : Resource = null
var _plugin : EditorPlugin = null
signal on_resource_changed(new_res)
func _enter_tree():
$ResourceButton.set_drag_forwarding(self)
func set_resource_type(type : String) -> void:
_resource_type = type
func set_resource(res : Resource) -> void:
if res && !res.is_class(_resource_type):
return
var emit : bool = res != _resource
_resource = res
refresh_ui()
if emit:
emit_signal("on_resource_changed", _resource)
func refresh_ui() -> void:
if _resource:
var text : String = _resource.resource_name
if text == "":
text = _resource.get_class()
$ResourceButton.text = text
else:
$ResourceButton.text = "[null]"
func on_clear_button_pressed() -> void:
if _resource:
set_resource(null)
func on_resource_button_pressed() -> void:
if _resource && _plugin:
_plugin.get_editor_interface().inspect_object(_resource)
#examples
#{files:[res://modules/planets/test_planet/test_world.tres], from:@@4176:[Tree:9070], type:files}
#{from:Button:[Button:917001], resource:[Resource:26180], type:resource}
func can_drop_data_fw(position, data, from_control):
return true
func drop_data_fw(position, data, from_control):
if data["type"] == "resource":
var res : Resource = data["resource"]
set_resource(res)
elif data["type"] == "files":
var files : Array = data["files"]
for f in files:
var res : Resource = load(f)
set_resource(res)
return
func get_drag_data_fw(position, from_control):
if !_resource:
return
var d : Dictionary = Dictionary()
d["from"] = self
d["resource"] = _resource
d["type"] = "resource"
return d
func set_plugin(plugin : EditorPlugin) -> void:
_plugin = plugin

View File

@ -0,0 +1,23 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/world_generator/widgets/EditorResourceWidget.gd" type="Script" id=1]
[node name="EditorResourceWidget" type="HBoxContainer"]
margin_right = 376.0
margin_bottom = 40.0
script = ExtResource( 1 )
[node name="ResourceButton" type="Button" parent="."]
margin_right = 342.0
margin_bottom = 40.0
size_flags_horizontal = 3
[node name="Clear" type="Button" parent="."]
margin_left = 346.0
margin_right = 376.0
margin_bottom = 40.0
rect_min_size = Vector2( 30, 0 )
text = "X"
[connection signal="pressed" from="ResourceButton" to="." method="on_resource_button_pressed"]
[connection signal="pressed" from="Clear" to="." method="on_clear_button_pressed"]

View File

@ -0,0 +1,220 @@
tool
extends HBoxContainer
#This is a port of godot 4.0's EditorZoomWidget
#/*************************************************************************/
#/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
#/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
#/* */
#/* Permission is hereby granted, free of charge, to any person obtaining */
#/* a copy of this software and associated documentation files (the */
#/* "Software"), to deal in the Software without restriction, including */
#/* without limitation the rights to use, copy, modify, merge, publish, */
#/* distribute, sublicense, and/or sell copies of the Software, and to */
#/* permit persons to whom the Software is furnished to do so, subject to */
#/* the following conditions: */
#/* */
#/* The above copyright notice and this permission notice shall be */
#/* included in all copies or substantial portions of the Software. */
#/* */
#/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
#/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
#/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
#/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
#/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
#/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
#/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#/*************************************************************************/
var zoom_minus : Button
var zoom_reset : Button
var zoom_plus : Button
var EDSCALE : float = 1
export(float) var zoom : float = 1.0 setget set_zoom, get_zoom
signal zoom_changed(zoom)
func _init() -> void:
# Zoom buttons
zoom_minus = Button.new()
zoom_minus.set_flat(true)
add_child(zoom_minus)
zoom_minus.connect("pressed", self, "_button_zoom_minus")
zoom_minus.set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_minus", tr("Zoom Out"), KEY_MASK_CMD | KEY_MINUS))
zoom_minus.set_focus_mode(FOCUS_NONE)
zoom_reset = Button.new()
zoom_reset.set_flat(true)
add_child(zoom_reset)
zoom_reset.add_theme_constant_override("outline_size", 1)
zoom_reset.add_theme_color_override("font_outline_color", Color(0, 0, 0))
zoom_reset.add_theme_color_override("font_color", Color(1, 1, 1))
zoom_reset.connect("pressed", self, "_button_zoom_reset")
zoom_reset.set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_reset", tr("Zoom Reset"), KEY_MASK_CMD | KEY_0))
zoom_reset.set_focus_mode(FOCUS_NONE)
#Prevent the button's size from changing when the text size changes
zoom_reset.set_custom_minimum_size(Vector2(75, 0))
zoom_plus = Button.new()
zoom_plus.set_flat(true)
add_child(zoom_plus)
zoom_plus.connect("pressed", self, "_button_zoom_plus")
zoom_plus.set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_plus", tr("Zoom In"), KEY_MASK_CMD | KEY_EQUAL)) # Usually direct access key for PLUS
zoom_plus.set_focus_mode(FOCUS_NONE)
_update_zoom_label()
add_theme_constant_override("separation", round(-8))
func get_zoom() -> float:
return zoom
func set_zoom(p_zoom : float) -> void:
if (p_zoom > 0 && p_zoom != zoom):
zoom = p_zoom;
_update_zoom_label();
emit_signal("zoom_changed", zoom);
func set_zoom_by_increments(p_increment_count : int, p_integer_only : bool) -> void:
# Remove editor scale from the index computation.
var zoom_noscale : float = zoom / max(1, EDSCALE)
var CMP_EPSILON : float = 0.00001
if (p_integer_only):
# Only visit integer scaling factors above 100%, and fractions with an integer denominator below 100%
# (1/2 = 50%, 1/3 = 33.33%, 1/4 = 25%, …).
# This is useful when working on pixel art projects to avoid distortion.
# This algorithm is designed to handle fractional start zoom values correctly
# (e.g. 190% will zoom up to 200% and down to 100%).
if (zoom_noscale + p_increment_count * 0.001 >= 1.0 - CMP_EPSILON):
# New zoom is certain to be above 100%.
if (p_increment_count >= 1):
# Zooming.
set_zoom(floor(zoom_noscale + p_increment_count) * max(1, EDSCALE))
else:
# Dezooming.
set_zoom(ceil(zoom_noscale + p_increment_count) * max(1, EDSCALE))
else:
if (p_increment_count >= 1):
# Zooming. Convert the current zoom into a denominator.
var new_zoom : float = 1.0 / ceil(1.0 / zoom_noscale - p_increment_count)
if (is_equal_approx(zoom_noscale, new_zoom)):
# New zoom is identical to the old zoom, so try again.
# This can happen due to floating-point precision issues.
new_zoom = 1.0 / ceil(1.0 / zoom_noscale - p_increment_count - 1)
set_zoom(new_zoom * max(1, EDSCALE));
else:
# Dezooming. Convert the current zoom into a denominator.
var new_zoom : float = 1.0 / floor(1.0 / zoom_noscale - p_increment_count)
if (is_equal_approx(zoom_noscale, new_zoom)):
# New zoom is identical to the old zoom, so try again.
# This can happen due to floating-point precision issues.
new_zoom = 1.0 / floor(1.0 / zoom_noscale - p_increment_count + 1)
set_zoom(new_zoom * max(1, EDSCALE))
else:
# Base increment factor defined as the twelveth root of two.
# This allow a smooth geometric evolution of the zoom, with the advantage of
# visiting all integer power of two scale factors.
# note: this is analogous to the 'semitones' interval in the music world
# In order to avoid numerical imprecisions, we compute and edit a zoom index
# with the following relation: zoom = 2 ^ (index / 12)
if (zoom < CMP_EPSILON || p_increment_count == 0):
return
# zoom = 2**(index/12) => log2(zoom) = index/12
var closest_zoom_index : float = round(log(zoom_noscale) * 12.0 / log(2.0))
var new_zoom_index : float = closest_zoom_index + p_increment_count
var new_zoom : float = pow(2.0, new_zoom_index / 12.0)
# Restore Editor scale transformation
new_zoom *= max(1, EDSCALE)
set_zoom(new_zoom)
func _update_zoom_label() -> void:
var zoom_text : String = ""
# The zoom level displayed is relative to the editor scale
# (like in most image editors). Its lower bound is clamped to 1 as some people
# lower the editor scale to increase the available real estate,
# even if their display doesn't have a particularly low DPI.
if (zoom >= 10):
# Don't show a decimal when the zoom level is higher than 1000 %.
#zoom_text = (rtos(round((zoom / max(1, EDSCALE)) * 100))) + " %"
zoom_text = (String(round((zoom / max(1, EDSCALE)) * 100))) + " %"
else:
var v : float = (zoom / max(1, EDSCALE)) * 100
var val : float = floor(v / 0.1 + 0.5) * 0.1
# zoom_text = (rtos(val)) + " %"
zoom_text = (String(val)) + " %"
zoom_reset.set_text(zoom_text)
func _button_zoom_minus() -> void:
set_zoom_by_increments(-6, Input.is_key_pressed(KEY_ALT));
emit_signal("zoom_changed", zoom);
func _button_zoom_reset() -> void:
set_zoom(1.0 * max(1, EDSCALE));
emit_signal("zoom_changed", zoom);
func _button_zoom_plus() -> void:
set_zoom_by_increments(6, Input.is_key_pressed(KEY_ALT));
emit_signal("zoom_changed", zoom);
func _notification(p_what : int) -> void:
if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED):
zoom_minus.icon = get_theme_icon("ZoomLess", "EditorIcons")
zoom_plus.icon = get_theme_icon("ZoomMore", "EditorIcons")
#from godot editor/editor_Settings.cpp
func ED_SHORTCUT(p_path : String, p_name : String, p_keycode : int, editor_settings : EditorSettings = null) -> ShortCut:
if OS.get_name() == "OSX":
# Use Cmd+Backspace as a general replacement for Delete shortcuts on macOS
if (p_keycode == KEY_DELETE):
p_keycode = KEY_MASK_CMD | KEY_BACKSPACE
var ie : InputEventKey = null
if (p_keycode):
ie = InputEventKey.new()
ie.set_unicode(p_keycode & KEY_CODE_MASK)
ie.set_scancode(p_keycode & KEY_CODE_MASK)
ie.set_shift(bool(p_keycode & KEY_MASK_SHIFT))
ie.set_alt(bool(p_keycode & KEY_MASK_ALT))
ie.set_control(bool(p_keycode & KEY_MASK_CTRL))
ie.set_metakey(bool(p_keycode & KEY_MASK_META))
if (!editor_settings):
var sc : ShortCut
sc = ShortCut.new()
sc.set_name(p_name)
sc.set_shortcut(ie)
sc.set_meta("original", ie)
return sc
var sc : ShortCut = editor_settings.get_shortcut(p_path)
if (sc.is_valid()):
sc.set_name(p_name); #keep name (the ones that come from disk have no name)
sc.set_meta("original", ie); #to compare against changes
return sc;
sc = ShortCut.new()
sc.set_name(p_name)
sc.set_shortcut(ie)
sc.set_meta("original", ie) #to compare against changes
editor_settings.add_shortcut(p_path, sc)
return sc

View File

@ -0,0 +1,8 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/world_generator/widgets/EditorZoomWidget.gd" type="Script" id=1]
[node name="EditorZoomWidget" type="HBoxContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 1 )

7
default_env.tres Normal file
View File

@ -0,0 +1,7 @@
[gd_resource type="Environment3D" load_steps=2 format=2]
[sub_resource type="ProceduralSky" id=1]
[resource]
background_mode = 2
background_sky = SubResource( 1 )

BIN
icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

35
icon.png.import Normal file
View File

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.png"
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

76
project.pandemonium Normal file
View File

@ -0,0 +1,76 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=4
_global_script_classes=[ {
"base": "Resource",
"class": @"Continent",
"language": @"GDScript",
"path": "res://addons/world_generator/resources/continent.gd"
}, {
"base": "Resource",
"class": @"SubZone",
"language": @"GDScript",
"path": "res://addons/world_generator/resources/subzone.gd"
}, {
"base": "Resource",
"class": @"SubZoneProp",
"language": @"GDScript",
"path": "res://addons/world_generator/resources/sub_zone_prop.gd"
}, {
"base": "Resource",
"class": @"WorldGenBaseResource",
"language": @"GDScript",
"path": "res://addons/world_generator/resources/world_gen_base_resource.gd"
}, {
"base": "Reference",
"class": @"WorldGenRaycast",
"language": @"GDScript",
"path": "res://addons/world_generator/raycast/world_gen_raycast.gd"
}, {
"base": "Resource",
"class": @"WorldGenWorld",
"language": @"GDScript",
"path": "res://addons/world_generator/resources/world_gen_world.gd"
}, {
"base": "Resource",
"class": @"WorldGeneratorSettings",
"language": @"GDScript",
"path": "res://addons/world_generator/resources/world_generator_settings.gd"
}, {
"base": "Resource",
"class": @"Zone",
"language": @"GDScript",
"path": "res://addons/world_generator/resources/zone.gd"
} ]
_global_script_class_icons={
@"WorldGenRaycast": "",
@"Continent": "",
@"SubZone": "",
@"SubZoneProp": "",
@"WorldGeneratorSettings": "",
@"WorldGenBaseResource": "",
@"WorldGenWorld": "",
@"Zone": ""
}
[application]
config/name="World Generator"
config/icon="res://icon.png"
[physics]
common/enable_pause_aware_picking=true
[rendering]
vram_compression/import_etc=true
vram_compression/import_etc2=false
environment/default_environment="res://default_env.tres"