From 9f3791b26936b27cd55b813d5b1ce274c8246f74 Mon Sep 17 00:00:00 2001 From: hop311 Date: Sun, 8 Dec 2024 22:29:38 +0000 Subject: [PATCH 01/10] Fix province icon scaling and detailed view handling --- extension/deps/openvic-simulation | 2 +- extension/doc_classes/MapItemSingleton.xml | 10 +- .../singletons/MapItemSingleton.cpp | 145 ++++++---- .../singletons/MapItemSingleton.hpp | 6 +- game/src/Game/GameSession/BillboardManager.gd | 259 ++++++++++-------- game/src/Game/GameSession/billboard.gdshader | 16 +- 6 files changed, 241 insertions(+), 197 deletions(-) diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation index 12157ce8..81305613 160000 --- a/extension/deps/openvic-simulation +++ b/extension/deps/openvic-simulation @@ -1 +1 @@ -Subproject commit 12157ce86d6a1a1637f9ef5f7feabe5650b7a993 +Subproject commit 813056134e39518275dd67e318e8262b90b5c082 diff --git a/extension/doc_classes/MapItemSingleton.xml b/extension/doc_classes/MapItemSingleton.xml index 1f72849e..27c55502 100644 --- a/extension/doc_classes/MapItemSingleton.xml +++ b/extension/doc_classes/MapItemSingleton.xml @@ -12,11 +12,6 @@ - - - - - @@ -27,6 +22,11 @@ + + + + + diff --git a/extension/src/openvic-extension/singletons/MapItemSingleton.cpp b/extension/src/openvic-extension/singletons/MapItemSingleton.cpp index b96b5786..d1145d6e 100644 --- a/extension/src/openvic-extension/singletons/MapItemSingleton.cpp +++ b/extension/src/openvic-extension/singletons/MapItemSingleton.cpp @@ -24,7 +24,7 @@ using namespace OpenVic; void MapItemSingleton::_bind_methods() { OV_BIND_METHOD(MapItemSingleton::get_billboards); OV_BIND_METHOD(MapItemSingleton::get_province_positions); - OV_BIND_METHOD(MapItemSingleton::get_capital_count); + OV_BIND_METHOD(MapItemSingleton::get_max_capital_count); OV_BIND_METHOD(MapItemSingleton::get_capital_positions); OV_BIND_METHOD(MapItemSingleton::get_crime_icons); OV_BIND_METHOD(MapItemSingleton::get_rgo_icons); @@ -46,7 +46,6 @@ MapItemSingleton::~MapItemSingleton() { } // Get the billboard object from the loaded objects - GFX::Billboard const* MapItemSingleton::get_billboard(std::string_view name, bool error_on_fail) const { GameSingleton const* game_singleton = GameSingleton::get_singleton(); ERR_FAIL_NULL_V(game_singleton, nullptr); @@ -55,7 +54,9 @@ GFX::Billboard const* MapItemSingleton::get_billboard(std::string_view name, boo game_singleton->get_definition_manager().get_ui_manager().get_cast_object_by_identifier(name); if (error_on_fail) { - ERR_FAIL_NULL_V_MSG(billboard, nullptr, vformat("Failed to find billboard \"%s\"", Utilities::std_to_godot_string(name))); + ERR_FAIL_NULL_V_MSG( + billboard, nullptr, vformat("Failed to find billboard \"%s\"", Utilities::std_to_godot_string(name)) + ); } return billboard; @@ -69,11 +70,9 @@ bool MapItemSingleton::add_billboard_dict(std::string_view name, TypedArray MapItemSingleton::get_billboards() const { GameSingleton const* game_singleton = GameSingleton::get_singleton(); @@ -100,30 +98,41 @@ TypedArray MapItemSingleton::get_billboards() const { add_billboard_dict(obj->get_name(), ret); } } - + return ret; } +// We assume GameSingleton isn't null when this is being called +static Vector2 get_billboard_pos(ProvinceDefinition const& province) { + return Utilities::to_godot_fvec2(province.get_city_position()) / GameSingleton::get_singleton()->get_map_dims(); +} + PackedVector2Array MapItemSingleton::get_province_positions() const { GameSingleton const* game_singleton = GameSingleton::get_singleton(); - ERR_FAIL_NULL_V(game_singleton, PackedVector2Array()); + ERR_FAIL_NULL_V(game_singleton, {}); + + MapDefinition const& map_definition = game_singleton->get_definition_manager().get_map_definition(); PackedVector2Array billboard_pos {}; - - for(ProvinceDefinition const& prov : game_singleton->get_definition_manager().get_map_definition().get_province_definitions()){ - if(prov.is_water()) continue; //billboards dont appear over water, skip - fvec2_t city_pos = prov.get_city_position(); - Vector2 pos = Utilities::to_godot_fvec2(city_pos) / game_singleton->get_map_dims(); - billboard_pos.push_back(pos); + billboard_pos.resize(map_definition.get_land_province_count()); + int64_t index = 0; + + for (ProvinceDefinition const& prov : map_definition.get_province_definitions()) { + if (prov.is_water()) { + // billboards dont appear over water, skip + continue; + } + + billboard_pos[index++] = get_billboard_pos(prov); } - + return billboard_pos; } //includes non-existent countries, used for setting the billboard buffer size -int32_t MapItemSingleton::get_capital_count() const { +int32_t MapItemSingleton::get_max_capital_count() const { GameSingleton const* game_singleton = GameSingleton::get_singleton(); ERR_FAIL_NULL_V(game_singleton, 0); @@ -132,68 +141,84 @@ int32_t MapItemSingleton::get_capital_count() const { PackedVector2Array MapItemSingleton::get_capital_positions() const { GameSingleton const* game_singleton = GameSingleton::get_singleton(); - ERR_FAIL_NULL_V(game_singleton, PackedVector2Array()); + ERR_FAIL_NULL_V(game_singleton, {}); InstanceManager const* instance_manager = game_singleton->get_instance_manager(); - ERR_FAIL_NULL_V(instance_manager, PackedVector2Array()); + ERR_FAIL_NULL_V(instance_manager, {}); + + CountryInstanceManager const& country_instance_manager = instance_manager->get_country_instance_manager(); PackedVector2Array billboard_pos {}; - for(CountryInstance const& country : instance_manager->get_country_instance_manager().get_country_instances()){ - if(!country.exists()) continue; //skip non-existant countries + billboard_pos.resize(country_instance_manager.get_country_instance_count()); - fvec2_t city_pos = country.get_capital()->get_province_definition().get_city_position(); - Vector2 pos = Utilities::to_godot_fvec2(city_pos) / game_singleton->get_map_dims(); - billboard_pos.push_back(pos); + int64_t index = 0; + for (CountryInstance const& country : country_instance_manager.get_country_instances()) { + if (!country.exists() || country.get_capital() == nullptr) { + //skip non-existent or capital-less countries + continue; + } + + billboard_pos[index++] = get_billboard_pos(country.get_capital()->get_province_definition()); } + billboard_pos.resize(index); + return billboard_pos; } PackedByteArray MapItemSingleton::get_crime_icons() const { GameSingleton const* game_singleton = GameSingleton::get_singleton(); - ERR_FAIL_NULL_V(game_singleton, PackedByteArray()); + ERR_FAIL_NULL_V(game_singleton, {}); InstanceManager const* instance_manager = game_singleton->get_instance_manager(); - ERR_FAIL_NULL_V(instance_manager, PackedByteArray()); + ERR_FAIL_NULL_V(instance_manager, {}); + + MapInstance const& map_instance = instance_manager->get_map_instance(); PackedByteArray icons {}; - for(ProvinceInstance const& prov_inst : instance_manager->get_map_instance().get_province_instances()){ - if (prov_inst.get_province_definition().is_water()) continue; //billboards dont appear over water, skip + icons.resize(map_instance.get_map_definition().get_land_province_count()); - if(prov_inst.get_crime() == nullptr){ - icons.push_back(0); //no crime on the province - } - else { - icons.push_back(prov_inst.get_crime()->get_icon()); + int64_t index = 0; + + for (ProvinceInstance const& prov_inst : map_instance.get_province_instances()) { + if (prov_inst.get_province_definition().is_water()) { + // billboards dont appear over water, skip + continue; } - + + Crime const* crime = prov_inst.get_crime(); + icons[index++] = crime != nullptr ? crime->get_icon() : 0; // 0 if no crime in the province } return icons; - } PackedByteArray MapItemSingleton::get_rgo_icons() const { GameSingleton const* game_singleton = GameSingleton::get_singleton(); - ERR_FAIL_NULL_V(game_singleton, PackedByteArray()); + ERR_FAIL_NULL_V(game_singleton, {}); InstanceManager const* instance_manager = game_singleton->get_instance_manager(); - ERR_FAIL_NULL_V(instance_manager, PackedByteArray()); + ERR_FAIL_NULL_V(instance_manager, {}); + + MapInstance const& map_instance = instance_manager->get_map_instance(); PackedByteArray icons {}; - for(ProvinceInstance const& prov_inst : instance_manager->get_map_instance().get_province_instances()){ - if (prov_inst.get_province_definition().is_water()) continue; //billboards dont appear over water, skip + icons.resize(map_instance.get_map_definition().get_land_province_count()); - if(prov_inst.get_rgo_good() == nullptr){ - icons.push_back(0); //no good on the province - } - else{ - icons.push_back(prov_inst.get_rgo_good()->get_index()+1); + int64_t index = 0; + + for (ProvinceInstance const& prov_inst : map_instance.get_province_instances()) { + if (prov_inst.get_province_definition().is_water()) { + // billboards dont appear over water, skip + continue; } + + GoodDefinition const* rgo_good = prov_inst.get_rgo_good(); + icons[index++] = rgo_good != nullptr ? rgo_good->get_index() + 1 : 0; // 0 if no rgo good in the province } return icons; @@ -210,28 +235,28 @@ TODO: National focus isn't implemented yet. It could be done at the country inst PackedByteArray MapItemSingleton::get_national_focus_icons() const { GameSingleton const* game_singleton = GameSingleton::get_singleton(); - ERR_FAIL_NULL_V(game_singleton, PackedByteArray()); + ERR_FAIL_NULL_V(game_singleton, {}); InstanceManager const* instance_manager = game_singleton->get_instance_manager(); - ERR_FAIL_NULL_V(instance_manager, PackedByteArray()); + ERR_FAIL_NULL_V(instance_manager, {}); + + MapInstance const& map_instance = instance_manager->get_map_instance(); PackedByteArray icons {}; - for(ProvinceInstance const& prov_inst : instance_manager->get_map_instance().get_province_instances()){ - if (prov_inst.get_province_definition().is_water()) continue; //billboards dont appear over water, skip + icons.resize(map_instance.get_map_definition().get_land_province_count()); - State const* state = prov_inst.get_state(); - if (state == nullptr) { - icons.push_back(0); - UtilityFunctions::push_warning( - "State for province ", Utilities::std_to_godot_string(prov_inst.get_identifier()), " was null" - ); - } else if (&prov_inst == state->get_capital()) { - icons.push_back(1); - } else { - icons.push_back(0); + int64_t index = 0; + + for (ProvinceInstance const& prov_inst : map_instance.get_province_instances()) { + if (prov_inst.get_province_definition().is_water()) { + // billboards dont appear over water, skip + continue; } + + State const* state = prov_inst.get_state(); + icons[index++] = state != nullptr && &prov_inst == state->get_capital() ? 1 : 0; } return icons; -} \ No newline at end of file +} diff --git a/extension/src/openvic-extension/singletons/MapItemSingleton.hpp b/extension/src/openvic-extension/singletons/MapItemSingleton.hpp index 479e9cec..867ac8d3 100644 --- a/extension/src/openvic-extension/singletons/MapItemSingleton.hpp +++ b/extension/src/openvic-extension/singletons/MapItemSingleton.hpp @@ -28,13 +28,11 @@ namespace OpenVic { bool add_billboard_dict(std::string_view name, godot::TypedArray& billboard_dict_array) const; godot::TypedArray get_billboards() const; godot::PackedVector2Array get_province_positions() const; - int32_t get_capital_count() const; + int32_t get_max_capital_count() const; godot::PackedVector2Array get_capital_positions() const; godot::PackedByteArray get_crime_icons() const; godot::PackedByteArray get_rgo_icons() const; godot::PackedByteArray get_national_focus_icons() const; - }; - -} \ No newline at end of file +} diff --git a/game/src/Game/GameSession/BillboardManager.gd b/game/src/Game/GameSession/BillboardManager.gd index 8b317715..f14986b8 100644 --- a/game/src/Game/GameSession/BillboardManager.gd +++ b/game/src/Game/GameSession/BillboardManager.gd @@ -1,32 +1,48 @@ extends MultiMeshInstance3D -#given a name: get the index for the texture in the shader -# this is to reduce the number of magic indeces in the code -# to get the proper billboard image -var billboard_names : Dictionary = {} - @export var _map_view : MapView -const SCALE_FACTOR : float = 1.0/96.0 - -enum ProvinceBillboards { NONE, INVISIBLE, RGO, CRIME, NATIONAL_FOCUS } +const SCALE_FACTOR : float = 1.0 / 96.0 + +enum BillboardType { NONE, RGO, CRIME, NATIONAL_FOCUS, CAPITAL } +const BILLBOARD_NAMES : Dictionary = { + BillboardType.RGO: &"tradegoods", + BillboardType.CRIME: &"crimes", + BillboardType.NATIONAL_FOCUS: &"national_focus", + BillboardType.CAPITAL: &"capital" +} +const BILLBOARD_DIMS : Dictionary = { + # Should be 0.8, but something else seems to be contributing to vertical + # stretching so we use 0.7 to account for that. + BillboardType.RGO: Vector2(1.0, 0.7), + + BillboardType.CRIME: Vector2(1.0, 1.0), + BillboardType.NATIONAL_FOCUS: Vector2(1.0, 1.0), + BillboardType.CAPITAL: Vector2(1.0, 1.0) +} enum MapModes { REVOLT_RISK = 2, INFRASTRUCTURE = 5, COLONIAL = 6, NATIONAL_FOCUS = 9, RGO_OUTPUT = 10 } var provinces_size : int = 0 var total_capitals_size : int = 0 -var textures : Array[Texture2D] = [] -var frames : Array[int] = [] -var scales : Array[float] = [] +# Given a BillboardType, get the index for the texture in the shader. +# This is to reduce the number of magic indeces in the code +# to get the proper billboard image +var billboard_type_to_index : Dictionary + +var textures : Array[Texture2D] +var frames : PackedByteArray +var scales : PackedVector2Array -var current_province_billboard : ProvinceBillboards = ProvinceBillboards.NONE +var current_province_billboard : BillboardType = BillboardType.NONE +var province_billboards_visible : bool = true # ============== Billboards ============= # Billboards are displayed using a multimesh (batch drawn mesh) # with positions set to every province and every nation capital. # A shader controls which billboard and frame from icon strips are displayed # at each province. It also makes billboards "look at" the camera -# To ensure billboards are displayed ontop of the map and units, it is contained in +# To ensure billboards are displayed ontop of the map and units, it is contained in # a subviewport which renders above the main viewport, with a camera set to follow the primary camera # multimesh only lets us send custom data to the shader as a single float vec4/Color variable @@ -38,125 +54,141 @@ var current_province_billboard : ProvinceBillboards = ProvinceBillboards.NONE # w: unused # "Province billboards" refer to billboards positioned on every province -# for map modes such as RGO output, while "Capital billboards" refers to the +# for map modes such as RGO output, while "Capital billboards" refers to the # to country capitals. func _ready() -> void: const name_key : StringName = &"name" const texture_key : StringName = &"texture" const scale_key : StringName = &"scale" - const noOfFrames_key : StringName = &"noFrames" - - var billboards : Array[Dictionary] = MapItemSingleton.get_billboards() - for j : int in billboards.size(): - var billboard : Dictionary = billboards[j] - - var billboard_name : String = billboard[name_key] - var texture_name : String = billboard[texture_key] + const no_of_frames_key : StringName = &"noFrames" + + for billboard : Dictionary in MapItemSingleton.get_billboards(): + var billboard_name : StringName = billboard[name_key] + + var billboard_type : BillboardType = BillboardType.NONE + for key : BillboardType in BILLBOARD_NAMES: + if billboard_name == BILLBOARD_NAMES[key]: + billboard_type = key + break + + if billboard_type == BillboardType.NONE: + continue + + var texture_name : StringName = billboard[texture_key] var billboard_scale : float = billboard[scale_key] - var noFrames : int = billboard[noOfFrames_key] - + var no_of_frames : int = billboard[no_of_frames_key] + #fix the alpha edges of the billboard textures - var texture : Texture2D = AssetManager.get_texture(texture_name) + var texture : ImageTexture = AssetManager.get_texture(texture_name) + if texture == null: + push_error("Texture for billboard \"", billboard_name, "\" was null!") + continue var image : Image = texture.get_image() image.fix_alpha_edges() texture.set_image(image) - + + # We use the texture array size (which will be the same as frames and scales' sizes) + # rather than billboard_index as the former only counts billboards we're actually using, + # while the latter counts all billboards defined in the game's GFX files + billboard_type_to_index[billboard_type] = textures.size() + textures.push_back(texture) - frames.push_back(noFrames) - scales.push_back(billboard_scale*SCALE_FACTOR) - billboard_names[billboard_name] = j - + frames.push_back(no_of_frames) + scales.push_back(BILLBOARD_DIMS[billboard_type] * billboard_scale * SCALE_FACTOR) + var material : ShaderMaterial = multimesh.mesh.surface_get_material(0) if material == null: push_error("ShaderMaterial for billboards was null") return - - material.set_shader_parameter("billboards",textures) - material.set_shader_parameter("numframes",frames) - material.set_shader_parameter("sizes",scales) - multimesh.mesh.surface_set_material(0,material) - + + material.set_shader_parameter(&"billboards", textures) + material.set_shader_parameter(&"numframes", frames) + material.set_shader_parameter(&"sizes", scales) + multimesh.mesh.surface_set_material(0, material) + var positions : PackedVector2Array = MapItemSingleton.get_province_positions() provinces_size = positions.size() - total_capitals_size = MapItemSingleton.get_capital_count() - + total_capitals_size = MapItemSingleton.get_max_capital_count() + # 1) setting instance_count clears and resizes the buffer # so we want to find the max size once and leave it # 2) resize must occur after setting the transform format multimesh.instance_count = provinces_size + total_capitals_size - multimesh.visible_instance_count = provinces_size + total_capitals_size - - set_capitals() - var map_positions : PackedVector3Array = to_map_coords(positions) + if _map_view == null: + push_error("MapView export varible for BillboardManager must be set!") + return - for i : int in positions.size(): - multimesh.set_instance_transform(i + total_capitals_size, Transform3D(Basis(), - map_positions[i] - )) + for province_index : int in provinces_size: + multimesh.set_instance_transform( + province_index + total_capitals_size, + Transform3D(Basis(), _map_view._map_to_world_coords(positions[province_index])) + ) + # These signals will trigger and update capitals and province icons right + # at the beginning of (as well as later throughout) the game session GameSingleton.mapmode_changed.connect(_on_map_mode_changed) GameSingleton.gamestate_updated.connect(_on_game_state_changed) -#TODO: Get rid of the vertical stretch, proper capitals placement - -#fetch the nation capitals and setup billboards for them +# Fetch the nation capitals and setup billboards for them func set_capitals() -> void: - var positions : PackedVector2Array = MapItemSingleton.get_capital_positions() - var capital_positions : PackedVector3Array = to_map_coords(positions) - var image_index : int = billboard_names["capital"] - - #multimesh.visible_instance_count = capitals_begin_index + capital_positions.size() - for i : int in capital_positions.size(): - multimesh.set_instance_transform(i,Transform3D(Basis(), - capital_positions[i] - )) - - #capital image, frame=1 ,2x unused - #frame=1 because frame=0 would cause capitals not to show - #and as an index its fine, since the shader UVs will wrap around + var capital_positions : PackedVector2Array = MapItemSingleton.get_capital_positions() + var capitals_size : int = capital_positions.size() + var image_index : int = billboard_type_to_index[BillboardType.CAPITAL] + + for capital_index : int in capitals_size: + multimesh.set_instance_transform( + capital_index, + Transform3D(Basis(), _map_view._map_to_world_coords(capital_positions[capital_index])) + ) + + # capital image, frame=1, 2x unused + # frame=1 because frame=0 would cause capitals not to show + # and as an index its fine, since the shader UVs will wrap around # 1.0 to 2.0 --> 0.0 to 1.0 so the capital image is preserved - multimesh.set_instance_custom_data(i,Color(#capital_index,Color( - image_index,1.0,0,0 - )) + multimesh.set_instance_custom_data( + capital_index, + Color(image_index, 1.0, 0.0, 0.0) + ) + # For every country that doesn't exist, make the capital invisible - for i : int in total_capitals_size - capital_positions.size(): - multimesh.set_instance_custom_data(capital_positions.size() + i, Color( - image_index,0.0,0,0 - )) - -# should provinces display RGO, crime, ..., or no billboard -func set_province_billboards(display : ProvinceBillboards = ProvinceBillboards.INVISIBLE) -> void: - var image_index : int = 0 - var icons : PackedByteArray = PackedByteArray() - icons.resize(provinces_size) - icons.fill(0) #by default, display nothing (invisible) - match display: - ProvinceBillboards.RGO: - image_index = billboard_names["tradegoods"] - icons = MapItemSingleton.get_rgo_icons() - current_province_billboard = display - ProvinceBillboards.CRIME: - image_index = billboard_names["crimes"] - icons = MapItemSingleton.get_crime_icons() - current_province_billboard = display - ProvinceBillboards.NATIONAL_FOCUS: - image_index = billboard_names["national_focus"] - icons = MapItemSingleton.get_national_focus_icons() - current_province_billboard = display - ProvinceBillboards.NONE: - current_province_billboard = display - _: #display nothing, but keep the current billboard setting - pass - # capitals are first in the array, so start iterating after them - for i : int in provinces_size: - multimesh.set_instance_custom_data(i + total_capitals_size,Color( - image_index,icons[i],0,0 - )) + for capital_index : int in range(capitals_size, total_capitals_size): + multimesh.set_instance_custom_data( + capital_index, + Color(image_index, 0.0, 0.0, 0.0) + ) + +# Should provinces display RGO, crime, ..., or no billboard +func update_province_billboards() -> void: + # If current_province_billboard is NONE then image_index will fall back to -1 + var image_index : int = billboard_type_to_index.get(current_province_billboard, -1) + if not province_billboards_visible or image_index < 0: + multimesh.visible_instance_count = total_capitals_size + else: + var icons : PackedByteArray + match current_province_billboard: + BillboardType.RGO: + icons = MapItemSingleton.get_rgo_icons() + BillboardType.CRIME: + icons = MapItemSingleton.get_crime_icons() + BillboardType.NATIONAL_FOCUS: + icons = MapItemSingleton.get_national_focus_icons() + _: + push_error("Invalid province billboard type: ", current_province_billboard) + return + + # Capitals are first in the array, so start iterating after them + for province_index : int in provinces_size: + multimesh.set_instance_custom_data( + province_index + total_capitals_size, + Color(image_index, icons[province_index], 0.0, 0.0) + ) + + multimesh.visible_instance_count = total_capitals_size + provinces_size func _on_game_state_changed() -> void: - set_province_billboards(current_province_billboard) + update_province_billboards() set_capitals() # There are essentially 3 visibility states we can be in @@ -166,33 +198,20 @@ func _on_game_state_changed() -> void: # So set_visible here is essentially to toggle the visibility of capitals func detailed_map(visible : bool) -> void: - if visible: - set_visible(true) - set_province_billboards(current_province_billboard) - else: - set_visible(true) - set_province_billboards() + province_billboards_visible = visible + update_province_billboards() func parchment_view(is_parchment : bool) -> void: - if is_parchment: - set_visible(false) - else: - detailed_map(false) + set_visible(not is_parchment) func _on_map_mode_changed(map_mode : int) -> void: match map_mode: MapModes.INFRASTRUCTURE, MapModes.COLONIAL, MapModes.RGO_OUTPUT: - set_province_billboards(ProvinceBillboards.RGO) + current_province_billboard = BillboardType.RGO MapModes.REVOLT_RISK: - set_province_billboards(ProvinceBillboards.CRIME) + current_province_billboard = BillboardType.CRIME MapModes.NATIONAL_FOCUS: - set_province_billboards(ProvinceBillboards.NATIONAL_FOCUS) + current_province_billboard = BillboardType.NATIONAL_FOCUS _: - set_province_billboards(ProvinceBillboards.NONE) - -func to_map_coords(positions : PackedVector2Array) -> PackedVector3Array: - var map_positions : PackedVector3Array = PackedVector3Array() - for pos_in : Vector2 in positions: - var pos : Vector3 = _map_view._map_to_world_coords(pos_in) - map_positions.push_back(pos) - return map_positions + current_province_billboard = BillboardType.NONE + update_province_billboards() diff --git a/game/src/Game/GameSession/billboard.gdshader b/game/src/Game/GameSession/billboard.gdshader index 417cedf4..bf15d2cd 100644 --- a/game/src/Game/GameSession/billboard.gdshader +++ b/game/src/Game/GameSession/billboard.gdshader @@ -4,11 +4,13 @@ shader_type spatial; //3d space. render_mode unshaded, depth_test_disabled; -//vic2 only ever loads a max of 12 BillboardType -//Of these, only 4 are actually used -uniform sampler2D billboards[12] : source_color; -uniform uint numframes[12]; -uniform float sizes[12]; +// Vic2 only ever loads a max of 12 BillboardType +// Of these, only 4 are actually used +const uint BILLBOARD_COUNT = 4u; + +uniform sampler2D billboards[BILLBOARD_COUNT] : source_color; +uniform uint numframes[BILLBOARD_COUNT]; +uniform vec2 sizes[BILLBOARD_COUNT]; //COLOR/INSTANCE_CUSTOM is our custom data, used as follows: // x=image index @@ -17,8 +19,8 @@ uniform float sizes[12]; void vertex() { COLOR = INSTANCE_CUSTOM; //send instance_custom info to fragment - float size = sizes[uint(COLOR.x + 0.5)]; - VERTEX = (vec4(VERTEX * size, 1.0) * VIEW_MATRIX).xyz; + VERTEX.xy *= sizes[uint(COLOR.x + 0.5)]; + VERTEX = (vec4(VERTEX, 1.0) * VIEW_MATRIX).xyz; } void fragment() { From 691e4e8c14598d1813e95242118503fc11da4e81 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 18:57:32 +0000 Subject: [PATCH 02/10] Bump extension/deps/openvic-simulation from `8130561` to `21d0aff` Bumps [extension/deps/openvic-simulation](https://github.com/OpenVicProject/OpenVic-Simulation) from `8130561` to `21d0aff`. - [Commits](https://github.com/OpenVicProject/OpenVic-Simulation/compare/813056134e39518275dd67e318e8262b90b5c082...21d0aff1325bdff4958657a220036b4e5393a037) --- updated-dependencies: - dependency-name: extension/deps/openvic-simulation dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- extension/deps/openvic-simulation | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation index 81305613..21d0aff1 160000 --- a/extension/deps/openvic-simulation +++ b/extension/deps/openvic-simulation @@ -1 +1 @@ -Subproject commit 813056134e39518275dd67e318e8262b90b5c082 +Subproject commit 21d0aff1325bdff4958657a220036b4e5393a037 From 5467a8d16825967bc095f7eefc40de68d4ce4b6e Mon Sep 17 00:00:00 2001 From: Nemrav <> Date: Mon, 16 Dec 2024 13:18:57 -0400 Subject: [PATCH 03/10] fix sp infantry --- game/src/Game/Model/XACLoader.gd | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/game/src/Game/Model/XACLoader.gd b/game/src/Game/Model/XACLoader.gd index c16d1cdf..423c6222 100644 --- a/game/src/Game/Model/XACLoader.gd +++ b/game/src/Game/Model/XACLoader.gd @@ -142,13 +142,6 @@ static func _load_xac_model(source_file : String, is_unit : bool) -> Node3D: push_warning("Skipping unused mesh \"", mesh_chunk_name, "\" in model \"", node.name, "\"") continue - # polySurface97 corresponds to the "arab_infantry_helmet", and needs to be removed often - # but only in cases where it isn't an attachment - const INVALID_IF_NOT_ONLY_MESH : PackedStringArray = ["polySurface97"] - if mesh_chunks.size() != 1 and mesh_chunk_name in INVALID_IF_NOT_ONLY_MESH: - push_warning("Skipping unused mesh \"", mesh_chunk_name, "\" in model \"", node.name, "\" because it was not the only mesh chunk in its file") - break - var mesh : ArrayMesh = null var verts : PackedVector3Array var normals : PackedVector3Array @@ -200,6 +193,16 @@ static func _load_xac_model(source_file : String, is_unit : bool) -> Node3D: skinning_chunk_ind = 1 applyVertexWeights = false + # polySurface97 corresponds to the "arab_infantry_helmet", and needs to be removed often + # but only in cases where it isn't an attachment + # problem, this is also the body of the S-P infantry + # so this should only be valid if inside an attachment or makes use of bone weights + const INVALID_IF_NOT_ONLY_MESH : PackedStringArray = ["polySurface97"] + if influenceRangeInd.is_empty() or skinningChunks.is_empty() or not applyVertexWeights: + if mesh_chunks.size() != 1 and mesh_chunk_name in INVALID_IF_NOT_ONLY_MESH: + push_warning("Skipping unused mesh \"", mesh_chunk_name, "\" in model \"", node.name, "\" because it was not the only mesh chunk in its file") + break + var meshInstance : MeshInstance3D = MeshInstance3D.new() node.add_child(meshInstance) meshInstance.owner = node From 509417f40702092651691d0c8a7548e6e686cf55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 18:16:49 +0000 Subject: [PATCH 04/10] Bump extension/deps/openvic-simulation from `21d0aff` to `a9f3012` Bumps [extension/deps/openvic-simulation](https://github.com/OpenVicProject/OpenVic-Simulation) from `21d0aff` to `a9f3012`. - [Commits](https://github.com/OpenVicProject/OpenVic-Simulation/compare/21d0aff1325bdff4958657a220036b4e5393a037...a9f30121f5f886ee2a8d615cca438278b1bb6f28) --- updated-dependencies: - dependency-name: extension/deps/openvic-simulation dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- extension/deps/openvic-simulation | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation index 21d0aff1..a9f30121 160000 --- a/extension/deps/openvic-simulation +++ b/extension/deps/openvic-simulation @@ -1 +1 @@ -Subproject commit 21d0aff1325bdff4958657a220036b4e5393a037 +Subproject commit a9f30121f5f886ee2a8d615cca438278b1bb6f28 From 8e1d25b5c5f47b785e5fa5927b1cac6afe06d3de Mon Sep 17 00:00:00 2001 From: Spartan322 Date: Sat, 14 Dec 2024 06:11:54 -0500 Subject: [PATCH 05/10] Add player customizable button hotkeys Fix potential button generation fail for invalid hotkeys Add Keychain action grouping organization Change default action map_zoom_in from Q to Shift+Q Change default action map_zoom_out from E to Shift+E Add `Keychain.reload_keychain` signal Add `keep_binding_check` Callable to Keychain.gd Prevents removal of unfounded action bindings Update Orama-Interactive/Keychain@0ddeb6fd4f40438d09551ada475668b91ce23dea --- .../src/openvic-extension/utility/UITools.cpp | 102 +++++++++++++----- game/addons/keychain/Keychain.gd | 26 ++++- game/addons/keychain/ShortcutEdit.gd | 10 +- game/addons/keychain/ShortcutEdit.tscn | 5 + game/addons/keychain/ShortcutProfile.gd | 3 + game/addons/keychain/assets/add.svg | 2 +- game/addons/keychain/assets/close.svg | 2 +- game/addons/keychain/assets/edit.svg | 2 +- game/addons/keychain/assets/folder.svg | 2 +- game/addons/keychain/assets/keyboard.svg | 2 +- .../keychain/assets/keyboard_physical.svg | 2 +- game/addons/keychain/assets/mouse.svg | 2 +- game/addons/keychain/assets/shortcut.svg | 2 +- .../keychain/translations/Translations.pot | 4 +- game/addons/keychain/translations/el_GR.po | 8 +- game/assets/localisation/locales/helpers.csv | 2 + .../localisation/locales/helpers.csv.import | 17 +++ game/project.godot | 5 +- game/src/Game/GameSession/GameSession.gd | 2 + game/src/Game/GameStart.gd | 26 +++++ game/src/Game/Menu/OptionMenu/OptionsMenu.gd | 23 ++++ 21 files changed, 200 insertions(+), 49 deletions(-) create mode 100644 game/assets/localisation/locales/helpers.csv create mode 100644 game/assets/localisation/locales/helpers.csv.import diff --git a/extension/src/openvic-extension/utility/UITools.cpp b/extension/src/openvic-extension/utility/UITools.cpp index 0dd17678..544ea989 100644 --- a/extension/src/openvic-extension/utility/UITools.cpp +++ b/extension/src/openvic-extension/utility/UITools.cpp @@ -1,14 +1,23 @@ #include "UITools.hpp" + #include +#include #include +#include +#include +#include +#include #include #include #include +#include #include #include #include +#include #include +#include #include "openvic-extension/classes/GUIButton.hpp" #include "openvic-extension/classes/GUIIcon.hpp" @@ -24,10 +33,6 @@ #include "openvic-extension/singletons/AssetManager.hpp" #include "openvic-extension/singletons/GameSingleton.hpp" #include "openvic-extension/utility/Utilities.hpp" -#include "godot_cpp/classes/global_constants.hpp" -#include "godot_cpp/classes/input_event_key.hpp" -#include "godot_cpp/classes/shortcut.hpp" -#include "godot_cpp/core/error_macros.hpp" using namespace godot; using namespace OpenVic; @@ -68,7 +73,7 @@ GUI::Position const* UITools::get_gui_position(String const& gui_scene, String c static Array get_events_from_shortcut_key(String const& key) { Array events; - if (key.length() == 0) { + if (key.is_empty()) { return events; } @@ -123,6 +128,69 @@ static Array get_events_from_shortcut_key(String const& key) { return events; } +static Error try_create_shortcut_action_for_button( + GUIButton* gui_button, String const& shortcut_key_name, String const& shortcut_hotkey_name = "" +) { + if (shortcut_key_name.is_empty()) { + return OK; + } + + Array event_array = get_events_from_shortcut_key(shortcut_key_name); + + ERR_FAIL_COND_V_MSG( + event_array.is_empty(), ERR_INVALID_PARAMETER, + vformat("Unknown shortcut key '%s' for GUI button %s", shortcut_key_name, gui_button->get_name()) + ); + + InputMap* const im = InputMap::get_singleton(); + String action_name; + if (shortcut_hotkey_name.is_empty()) { + action_name = // + vformat("button_%s_hotkey", gui_button->get_name().to_lower().replace("button", "").replace("hotkey", "")) + .replace("__", "_"); + } else { + action_name = vformat("button_%s_hotkey", shortcut_hotkey_name); + } + Ref action_event; + action_event.instantiate(); + action_event->set_action(action_name); + action_event->set_pressed(true); + + if (im->has_action(action_name)) { + TypedArray events = im->action_get_events(action_name); + bool should_warn = events.size() != event_array.size(); + if (!should_warn) { + for (std::size_t index = 0; index < events.size(); index++) { + if (!event_array.has(events[index])) { + should_warn = true; + break; + } + } + } + + if (should_warn) { + WARN_PRINT(vformat("'%s' already found in InputMap with different values, reusing hotkey", action_name)); + } + } else { + im->add_action(action_name); + for (std::size_t index = 0; index < event_array.size(); index++) { + Ref event = event_array[index]; + ERR_CONTINUE(event.is_null()); + im->action_add_event(action_name, event); + } + } + + Array shortcut_array; + shortcut_array.push_back(action_event); + + Ref shortcut; + shortcut.instantiate(); + shortcut->set_events(shortcut_array); + gui_button->set_shortcut(shortcut); + + return OK; +} + /* GUI::Element tree -> godot::Control tree conversion code below: */ namespace OpenVic { @@ -283,12 +351,7 @@ static bool generate_button(generate_gui_args_t&& args) { // TODO - clicksound, rotation (?) const String button_name = Utilities::std_to_godot_string(button.get_name()); const String shortcut_key_name = Utilities::std_to_godot_string(button.get_shortcut()); - Array event_array = get_events_from_shortcut_key(shortcut_key_name); - ERR_FAIL_COND_V_MSG( - shortcut_key_name.length() != 0 && event_array.size() == 0, false, - vformat("Unknown shortcut key '%s' for GUI button %s", shortcut_key_name, button_name) - ); ERR_FAIL_NULL_V_MSG(button.get_sprite(), false, vformat("Null sprite for GUI button %s", button_name)); GUIButton* gui_button = nullptr; @@ -335,11 +398,8 @@ static bool generate_button(generate_gui_args_t&& args) { ret &= gui_button->set_gfx_font(button.get_font()) == OK; } - if (shortcut_key_name.length() != 0) { - Ref shortcut; - shortcut.instantiate(); - shortcut->set_events(event_array); - gui_button->set_shortcut(shortcut); + if (try_create_shortcut_action_for_button(gui_button, shortcut_key_name) != OK) { + WARN_PRINT(vformat("Failed to create shortcut for GUI button '%s'", button_name)); } gui_button->set_shortcut_feedback(false); @@ -354,12 +414,7 @@ static bool generate_checkbox(generate_gui_args_t&& args) { const String checkbox_name = Utilities::std_to_godot_string(checkbox.get_name()); const String shortcut_key_name = Utilities::std_to_godot_string(checkbox.get_shortcut()); - Array event_array = get_events_from_shortcut_key(shortcut_key_name); - ERR_FAIL_COND_V_MSG( - shortcut_key_name.length() != 0 && event_array.size() == 0, false, - vformat("Unknown shortcut key '%s' for GUI checkbox %s", shortcut_key_name, checkbox_name) - ); ERR_FAIL_NULL_V_MSG(checkbox.get_sprite(), false, vformat("Null sprite for GUI checkbox %s", checkbox_name)); GFX::IconTextureSprite const* texture_sprite = checkbox.get_sprite()->cast_to(); @@ -390,11 +445,8 @@ static bool generate_checkbox(generate_gui_args_t&& args) { ret &= gui_icon_button->set_gfx_font(checkbox.get_font()) == OK; } - if (shortcut_key_name.length() != 0) { - Ref shortcut; - shortcut.instantiate(); - shortcut->set_events(event_array); - gui_icon_button->set_shortcut(shortcut); + if (try_create_shortcut_action_for_button(gui_icon_button, shortcut_key_name) != OK) { + WARN_PRINT(vformat("Failed to create shortcut hotkey for GUI checkbox '%s'", checkbox_name)); } gui_icon_button->set_shortcut_feedback(false); diff --git a/game/addons/keychain/Keychain.gd b/game/addons/keychain/Keychain.gd index 2288107b..f99afb98 100644 --- a/game/addons/keychain/Keychain.gd +++ b/game/addons/keychain/Keychain.gd @@ -2,6 +2,8 @@ extends Node const PROFILES_PATH := "user://shortcut_profiles" +signal reload_keychain() + ## [Array] of [ShortcutProfile]s. var profiles: Array[ShortcutProfile] = [preload("profiles/default.tres")] var selected_profile := profiles[0] ## The currently selected [ShortcutProfile]. @@ -22,9 +24,12 @@ var ignore_ui_actions := true ## and the fourth for [InputEventJoypadMotion]s. var changeable_types: PackedByteArray = [true, true, true, true] ## The file path of the [code]config_file[/code]. -var config_path := "user://cache.ini" +var config_path := "user://config.ini" ## Used to store the settings to the filesystem. var config_file: ConfigFile +## Used to check if unused binding check should be ignored for action +var keep_binding_check : Callable = func(action_name : StringName) -> bool: + return action_name.begins_with("button_") and action_name.ends_with("_hotkey") class InputAction: @@ -48,6 +53,10 @@ class InputGroup: folded = _folded +func _init() -> void: + for locale in TranslationServer.get_loaded_locales(): + load_translation(locale) + func _ready() -> void: if !config_file: config_file = ConfigFile.new() @@ -58,11 +67,11 @@ func _ready() -> void: DirAccess.make_dir_recursive_absolute(PROFILES_PATH) var profile_dir := DirAccess.open(PROFILES_PATH) profile_dir.list_dir_begin() - var file_name = profile_dir.get_next() + var file_name := profile_dir.get_next() while file_name != "": if !profile_dir.current_is_dir(): if file_name.get_extension() == "tres": - var file = load(PROFILES_PATH.path_join(file_name)) + var file := load(PROFILES_PATH.path_join(file_name)) if file is ShortcutProfile: profiles.append(file) file_name = profile_dir.get_next() @@ -76,12 +85,15 @@ func _ready() -> void: if saved: profiles.append(profile) + initialize_profiles() + +func initialize_profiles() -> void: for profile in profiles: profile.fill_bindings() profile_index = config_file.get_value("shortcuts", "shortcuts_profile", 0) change_profile(profile_index) - + Keychain.reload_keychain.emit() func change_profile(index: int) -> void: if index >= profiles.size(): @@ -89,6 +101,7 @@ func change_profile(index: int) -> void: profile_index = index selected_profile = profiles[index] for action in selected_profile.bindings: + if not InputMap.has_action(action): continue action_erase_events(action) for event in selected_profile.bindings[action]: action_add_event(action, event) @@ -107,7 +120,10 @@ func action_erase_events(action: StringName) -> void: func load_translation(locale: String) -> void: - var translation = load("res://addons/keychain/translations".path_join(locale + ".po")) + var translation_file_path := "res://addons/keychain/translations".path_join(locale + ".po") + if not ResourceLoader.exists(translation_file_path, "Translation"): + return + var translation := load(translation_file_path) if is_instance_valid(translation) and translation is Translation: TranslationServer.add_translation(translation) diff --git a/game/addons/keychain/ShortcutEdit.gd b/game/addons/keychain/ShortcutEdit.gd index 207ddec1..40a4ee49 100644 --- a/game/addons/keychain/ShortcutEdit.gd +++ b/game/addons/keychain/ShortcutEdit.gd @@ -10,8 +10,8 @@ const MOUSE_BUTTON_NAMES: PackedStringArray = [ "Wheel Down Button", "Wheel Left Button", "Wheel Right Button", - "X Button 1", - "X Button 2", + "Mouse Thumb Button 1", + "Mouse Thumb Button 2", ] const JOY_BUTTON_NAMES: PackedStringArray = [ @@ -110,6 +110,10 @@ func _ready() -> void: if OS.get_name() == "Web": $VBoxContainer/HBoxContainer/OpenProfileFolder.queue_free() + Keychain.reload_keychain.connect(_on_reload_keychain) + +func _on_reload_keychain() -> void: + _on_ProfileOptionButton_item_selected(Keychain.profile_index) func _construct_tree() -> void: var buttons_disabled := false if Keychain.selected_profile.customizable else true @@ -271,7 +275,7 @@ func _on_shortcut_tree_button_clicked(item: TreeItem, _column: int, id: int, _mb rect.position.y += 42 - tree.get_scroll().y rect.position += global_position rect.size = Vector2(110, 23 * shortcut_type_menu.get_item_count()) - shortcut_type_menu.popup(rect) + shortcut_type_menu.popup_on_parent(rect) elif id == 1: # Delete Keychain.action_erase_events(action) Keychain.selected_profile.change_action(action) diff --git a/game/addons/keychain/ShortcutEdit.tscn b/game/addons/keychain/ShortcutEdit.tscn index 57bfd46c..2e46a0e5 100644 --- a/game/addons/keychain/ShortcutEdit.tscn +++ b/game/addons/keychain/ShortcutEdit.tscn @@ -35,25 +35,30 @@ text = "Shortcut profile:" [node name="ProfileOptionButton" type="OptionButton" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 +size_flags_horizontal = 3 mouse_default_cursor_shape = 2 [node name="NewProfile" type="Button" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 +size_flags_horizontal = 3 mouse_default_cursor_shape = 2 text = "New" [node name="RenameProfile" type="Button" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 +size_flags_horizontal = 3 mouse_default_cursor_shape = 2 text = "Rename" [node name="DeleteProfile" type="Button" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 +size_flags_horizontal = 3 mouse_default_cursor_shape = 2 text = "Delete" [node name="OpenProfileFolder" type="Button" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 +size_flags_horizontal = 3 mouse_default_cursor_shape = 2 text = "Open Folder" diff --git a/game/addons/keychain/ShortcutProfile.gd b/game/addons/keychain/ShortcutProfile.gd index 0fb269a1..ee548744 100644 --- a/game/addons/keychain/ShortcutProfile.gd +++ b/game/addons/keychain/ShortcutProfile.gd @@ -17,6 +17,9 @@ func fill_bindings() -> void: bindings[action] = InputMap.action_get_events(action) unnecessary_actions.erase(action) for action in unnecessary_actions: + if Keychain.keep_binding_check.call(action): + unnecessary_actions.erase(action) + continue bindings.erase(action) save() diff --git a/game/addons/keychain/assets/add.svg b/game/addons/keychain/assets/add.svg index afad08a2..b0fdf8a3 100644 --- a/game/addons/keychain/assets/add.svg +++ b/game/addons/keychain/assets/add.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/game/addons/keychain/assets/close.svg b/game/addons/keychain/assets/close.svg index 331727ab..fc587082 100644 --- a/game/addons/keychain/assets/close.svg +++ b/game/addons/keychain/assets/close.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/game/addons/keychain/assets/edit.svg b/game/addons/keychain/assets/edit.svg index 6fc7ae01..925f7930 100644 --- a/game/addons/keychain/assets/edit.svg +++ b/game/addons/keychain/assets/edit.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/game/addons/keychain/assets/folder.svg b/game/addons/keychain/assets/folder.svg index c2def257..904f94b2 100644 --- a/game/addons/keychain/assets/folder.svg +++ b/game/addons/keychain/assets/folder.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/game/addons/keychain/assets/keyboard.svg b/game/addons/keychain/assets/keyboard.svg index b9dfab71..ab6755c8 100644 --- a/game/addons/keychain/assets/keyboard.svg +++ b/game/addons/keychain/assets/keyboard.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/game/addons/keychain/assets/keyboard_physical.svg b/game/addons/keychain/assets/keyboard_physical.svg index 4364e0b4..f12cd461 100644 --- a/game/addons/keychain/assets/keyboard_physical.svg +++ b/game/addons/keychain/assets/keyboard_physical.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/game/addons/keychain/assets/mouse.svg b/game/addons/keychain/assets/mouse.svg index 21751208..2dcc03e1 100644 --- a/game/addons/keychain/assets/mouse.svg +++ b/game/addons/keychain/assets/mouse.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/game/addons/keychain/assets/shortcut.svg b/game/addons/keychain/assets/shortcut.svg index 4ef16f04..87b1a40e 100644 --- a/game/addons/keychain/assets/shortcut.svg +++ b/game/addons/keychain/assets/shortcut.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/game/addons/keychain/translations/Translations.pot b/game/addons/keychain/translations/Translations.pot index 1f10c772..752a8c8c 100644 --- a/game/addons/keychain/translations/Translations.pot +++ b/game/addons/keychain/translations/Translations.pot @@ -103,10 +103,10 @@ msgstr "" msgid "Wheel Right Button" msgstr "" -msgid "X Button 1" +msgid "Mouse Thumb Button 1" msgstr "" -msgid "X Button 2" +msgid "Mouse Thumb Button 2" msgstr "" msgid "DualShock Cross, Xbox A, Nintendo B" diff --git a/game/addons/keychain/translations/el_GR.po b/game/addons/keychain/translations/el_GR.po index 4b6ce8bb..1ac87482 100644 --- a/game/addons/keychain/translations/el_GR.po +++ b/game/addons/keychain/translations/el_GR.po @@ -109,11 +109,11 @@ msgstr "Τρόχος αριστερά" msgid "Wheel Right Button" msgstr "Τρόχος δεξιά" -msgid "X Button 1" -msgstr "Κουμπί X 1" +msgid "Mouse Thumb Button 1" +msgstr "Κουμπί αντίχειρα ποντικού 1" -msgid "X Button 2" -msgstr "Κουμπί X 2" +msgid "Mouse Thumb Button 2" +msgstr "Κουμπί αντίχειρα ποντικιού 2" msgid "DualShock Cross, Xbox A, Nintendo B" msgstr "DualShock Σταυρός, Xbox A, Nintendo B" diff --git a/game/assets/localisation/locales/helpers.csv b/game/assets/localisation/locales/helpers.csv new file mode 100644 index 00000000..76853cc3 --- /dev/null +++ b/game/assets/localisation/locales/helpers.csv @@ -0,0 +1,2 @@ +keys;en;fr;de;es +Mapmode %s;Mapmode %s;Mode De Carte %s;Kartenmodus %s;Modo Mapa %s \ No newline at end of file diff --git a/game/assets/localisation/locales/helpers.csv.import b/game/assets/localisation/locales/helpers.csv.import new file mode 100644 index 00000000..2a5dbb39 --- /dev/null +++ b/game/assets/localisation/locales/helpers.csv.import @@ -0,0 +1,17 @@ +[remap] + +importer="csv_translation" +type="Translation" +uid="uid://dfro7ae4a6gkc" + +[deps] + +files=["res://assets/localisation/locales/helpers.en.translation", "res://assets/localisation/locales/helpers.fr.translation", "res://assets/localisation/locales/helpers.de.translation", "res://assets/localisation/locales/helpers.es.translation"] + +source_file="res://assets/localisation/locales/helpers.csv" +dest_files=["res://assets/localisation/locales/helpers.en.translation", "res://assets/localisation/locales/helpers.fr.translation", "res://assets/localisation/locales/helpers.de.translation", "res://assets/localisation/locales/helpers.es.translation"] + +[params] + +compress=false +delimiter=1 diff --git a/game/project.godot b/game/project.godot index 13883395..cd3e6641 100644 --- a/game/project.godot +++ b/game/project.godot @@ -95,13 +95,13 @@ map_west={ map_zoom_in={ "deadzone": 0.5, "events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":8,"position":Vector2(174, 17),"global_position":Vector2(180, 80),"factor":1.0,"button_index":4,"canceled":false,"pressed":true,"double_click":false,"script":null) -, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":81,"physical_keycode":0,"key_label":0,"unicode":113,"location":0,"echo":false,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":81,"physical_keycode":0,"key_label":0,"unicode":113,"location":0,"echo":false,"script":null) ] } map_zoom_out={ "deadzone": 0.5, "events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":16,"position":Vector2(325, 24),"global_position":Vector2(331, 87),"factor":1.0,"button_index":5,"canceled":false,"pressed":true,"double_click":false,"script":null) -, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":69,"physical_keycode":0,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":69,"physical_keycode":0,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null) ] } map_drag={ @@ -145,6 +145,7 @@ menu_pause={ [internationalization] locale/translation_remaps={} +locale/translations=PackedStringArray("res://assets/localisation/locales/helpers.de.translation", "res://assets/localisation/locales/helpers.en.translation", "res://assets/localisation/locales/helpers.es.translation", "res://assets/localisation/locales/helpers.fr.translation") locale/fallback="en_GB" locale/locale_filter_mode=0 locale/country_short_name={ diff --git a/game/src/Game/GameSession/GameSession.gd b/game/src/Game/GameSession/GameSession.gd index 9d07fd6a..1fac9d5c 100644 --- a/game/src/Game/GameSession/GameSession.gd +++ b/game/src/Game/GameSession/GameSession.gd @@ -13,6 +13,8 @@ func _ready() -> void: MusicConductor.generate_playlist() MusicConductor.select_next_song() + Keychain.initialize_profiles() + func _process(_delta : float) -> void: GameSingleton.update_clock() diff --git a/game/src/Game/GameStart.gd b/game/src/Game/GameStart.gd index 837e7127..a2be2f14 100644 --- a/game/src/Game/GameStart.gd +++ b/game/src/Game/GameStart.gd @@ -16,6 +16,32 @@ var _settings_base_path : String = "" var _compatibility_path_list : PackedStringArray = [] func _ready() -> void: + Keychain.actions = { + # Map Group + &"map_north": Keychain.InputAction.new("Move North", "Map", true), + &"map_east": Keychain.InputAction.new("Move East", "Map", true), + &"map_south": Keychain.InputAction.new("Move South", "Map", true), + &"map_west": Keychain.InputAction.new("Move West", "Map", true), + &"map_zoom_in": Keychain.InputAction.new("Zoom In", "Map", true), + &"map_zoom_out": Keychain.InputAction.new("Zoom Out", "Map", true), + &"map_drag": Keychain.InputAction.new("Mouse Drag", "Map", true), + &"map_click": Keychain.InputAction.new("Mouse Click", "Map", true), + &"map_right_click": Keychain.InputAction.new("Mouse Right Click", "Map", true), + # Time Group + &"time_pause": Keychain.InputAction.new("Pause", "Time", true), + &"time_speed_increase": Keychain.InputAction.new("Speed Increase", "Time", true), + &"time_speed_decrease": Keychain.InputAction.new("Speed Decrease", "Time", true), + # UI Group + &"menu_pause": Keychain.InputAction.new("Open Pause Menu", "UI", true), + } + + Keychain.groups = { + "Map": Keychain.InputGroup.new("", false), + "Time": Keychain.InputGroup.new("", false), + "UI": Keychain.InputGroup.new("", false), + "Hotkeys": Keychain.InputGroup.new("UI") + } + Localisation.initialize() if ArgumentParser.get_argument(&"help"): ArgumentParser._print_help() diff --git a/game/src/Game/Menu/OptionMenu/OptionsMenu.gd b/game/src/Game/Menu/OptionMenu/OptionsMenu.gd index 2b70d1ca..c487fb46 100644 --- a/game/src/Game/Menu/OptionMenu/OptionsMenu.gd +++ b/game/src/Game/Menu/OptionMenu/OptionsMenu.gd @@ -14,6 +14,29 @@ func _ready() -> void: _tab_container.set_tab_title(3, "OPTIONS_CONTROLS") _tab_container.set_tab_title(4, "OPTIONS_OTHER") + # Setup Keychain for Hotkeys + for action : StringName in InputMap.get_actions(): + if not Keychain.keep_binding_check.call(action): + continue + Keychain.actions[action] = Keychain.InputAction.new( + action.erase(0, "button_".length()).left(-"_hotkey".length()).capitalize(), + "Hotkeys") + var display_name : String = Keychain.actions[action].display_name + if display_name.begins_with("Mapmode"): + var mapmode_index := display_name.replace("Mapmode", "").to_int() + display_name = tr(GameSingleton.get_mapmode_localisation_key(mapmode_index)) + if mapmode_index <= 10: + display_name = display_name\ + .replace(" Mapmode", "")\ + .replace("Mode de carte ", "")\ + .replace("-Kartenmodus", "")\ + .replace("Modo de mapa de ", "")\ + .replace("Modo mapa de ", "")\ + .replace("Modo mapa ", "") + display_name = tr("Mapmode %s") % display_name.capitalize() + Keychain.actions[action].display_name = display_name + Keychain.profiles[0].bindings[action] = InputMap.action_get_events(action) + # Prepare options menu before loading user settings var tab_bar : TabBar = _tab_container.get_child(0, true) From 4929a54255870b4a69b8042653168394a450eced Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:21:38 +0000 Subject: [PATCH 06/10] Bump extension/deps/openvic-simulation from `a9f3012` to `d80df8d` Bumps [extension/deps/openvic-simulation](https://github.com/OpenVicProject/OpenVic-Simulation) from `a9f3012` to `d80df8d`. - [Commits](https://github.com/OpenVicProject/OpenVic-Simulation/compare/a9f30121f5f886ee2a8d615cca438278b1bb6f28...d80df8d44ff446543884ae9dafa50b7071476f2a) --- updated-dependencies: - dependency-name: extension/deps/openvic-simulation dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- extension/deps/openvic-simulation | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation index a9f30121..d80df8d4 160000 --- a/extension/deps/openvic-simulation +++ b/extension/deps/openvic-simulation @@ -1 +1 @@ -Subproject commit a9f30121f5f886ee2a8d615cca438278b1bb6f28 +Subproject commit d80df8d44ff446543884ae9dafa50b7071476f2a From fc99e2556de571be693144296accfe4e569c37bd Mon Sep 17 00:00:00 2001 From: Spartan322 Date: Wed, 18 Dec 2024 14:55:46 -0500 Subject: [PATCH 07/10] Move keep_binding_check definition to GameStart.gd --- game/addons/keychain/Keychain.gd | 2 +- game/addons/keychain/ShortcutProfile.gd | 2 +- game/src/Game/GameStart.gd | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/game/addons/keychain/Keychain.gd b/game/addons/keychain/Keychain.gd index f99afb98..99611894 100644 --- a/game/addons/keychain/Keychain.gd +++ b/game/addons/keychain/Keychain.gd @@ -29,7 +29,7 @@ var config_path := "user://config.ini" var config_file: ConfigFile ## Used to check if unused binding check should be ignored for action var keep_binding_check : Callable = func(action_name : StringName) -> bool: - return action_name.begins_with("button_") and action_name.ends_with("_hotkey") + return false class InputAction: diff --git a/game/addons/keychain/ShortcutProfile.gd b/game/addons/keychain/ShortcutProfile.gd index ee548744..e7935a3b 100644 --- a/game/addons/keychain/ShortcutProfile.gd +++ b/game/addons/keychain/ShortcutProfile.gd @@ -17,7 +17,7 @@ func fill_bindings() -> void: bindings[action] = InputMap.action_get_events(action) unnecessary_actions.erase(action) for action in unnecessary_actions: - if Keychain.keep_binding_check.call(action): + if Keychain.keep_binding_check.is_valid() and Keychain.keep_binding_check.call(action): unnecessary_actions.erase(action) continue bindings.erase(action) diff --git a/game/src/Game/GameStart.gd b/game/src/Game/GameStart.gd index a2be2f14..760da7a5 100644 --- a/game/src/Game/GameStart.gd +++ b/game/src/Game/GameStart.gd @@ -15,6 +15,10 @@ const GameMenuScene := preload("res://src/Game/GameMenu.tscn") var _settings_base_path : String = "" var _compatibility_path_list : PackedStringArray = [] +func _enter_tree() -> void: + Keychain.keep_binding_check = func(action_name : StringName) -> bool: + return action_name.begins_with("button_") and action_name.ends_with("_hotkey") + func _ready() -> void: Keychain.actions = { # Map Group From a166a6c201b05dfa79f9dd22702d852bd902fe0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 00:08:53 +0000 Subject: [PATCH 08/10] Bump extension/deps/openvic-simulation from `d80df8d` to `1072b37` Bumps [extension/deps/openvic-simulation](https://github.com/OpenVicProject/OpenVic-Simulation) from `d80df8d` to `1072b37`. - [Commits](https://github.com/OpenVicProject/OpenVic-Simulation/compare/d80df8d44ff446543884ae9dafa50b7071476f2a...1072b378c6c236c0c60cc544cf3c02c59dcfbc31) --- updated-dependencies: - dependency-name: extension/deps/openvic-simulation dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- extension/deps/openvic-simulation | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation index d80df8d4..1072b378 160000 --- a/extension/deps/openvic-simulation +++ b/extension/deps/openvic-simulation @@ -1 +1 @@ -Subproject commit d80df8d44ff446543884ae9dafa50b7071476f2a +Subproject commit 1072b378c6c236c0c60cc544cf3c02c59dcfbc31 From 2e9bc3dc24cabe7664ccafc5ad766a11d122b2c9 Mon Sep 17 00:00:00 2001 From: Spartan322 Date: Thu, 19 Dec 2024 03:16:39 -0500 Subject: [PATCH 09/10] Correct dependabot to focus on OpenVic submodules --- .github/dependabot.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index db664508..a9f8e79f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,3 +4,6 @@ updates: directory: "/" schedule: interval: "daily" + allow: + - dependency-name: "extension/deps/openvic-simulation" + - dependency-name: "scripts" From 1c338c2e8d48b935a9c8b0754375da75aed34622 Mon Sep 17 00:00:00 2001 From: hop311 Date: Fri, 20 Dec 2024 23:55:31 +0000 Subject: [PATCH 10/10] Update SIM repo to include pop stat distributions --- extension/deps/openvic-simulation | 2 +- .../singletons/PopulationMenu.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/extension/deps/openvic-simulation b/extension/deps/openvic-simulation index 1072b378..e594a7e4 160000 --- a/extension/deps/openvic-simulation +++ b/extension/deps/openvic-simulation @@ -1 +1 @@ -Subproject commit 1072b378c6c236c0c60cc544cf3c02c59dcfbc31 +Subproject commit e594a7e4954b33df714f17b857757478b074d054 diff --git a/extension/src/openvic-extension/singletons/PopulationMenu.cpp b/extension/src/openvic-extension/singletons/PopulationMenu.cpp index 29f30aca..e2db7c7b 100644 --- a/extension/src/openvic-extension/singletons/PopulationMenu.cpp +++ b/extension/src/openvic-extension/singletons/PopulationMenu.cpp @@ -397,10 +397,10 @@ Error MenuSingleton::_population_menu_update_filtered_pops() { population_menu.workforce_distribution[pop->get_type()] += pop_size; population_menu.religion_distribution[&pop->get_religion()] += pop_size; - population_menu.ideology_distribution += pop->get_ideologies() * pop_size; + population_menu.ideology_distribution += pop->get_ideology_distribution() * pop_size; population_menu.culture_distribution[&pop->get_culture()] += pop_size; - population_menu.issue_distribution += pop->get_issues() * pop_size; - population_menu.vote_distribution += pop->get_votes() * pop_size; + population_menu.issue_distribution += pop->get_issue_distribution() * pop_size; + population_menu.vote_distribution += pop->get_vote_distribution() * pop_size; } normalise_fixed_point_map(population_menu.workforce_distribution); @@ -455,11 +455,11 @@ MenuSingleton::sort_func_t MenuSingleton::_get_population_menu_sort_func(PopSort }; case SORT_IDEOLOGY: return [](Pop const* a, Pop const* b) -> bool { - return sorted_indexed_map_less_than(a->get_ideologies(), b->get_ideologies()); + return sorted_indexed_map_less_than(a->get_ideology_distribution(), b->get_ideology_distribution()); }; case SORT_ISSUES: return [](Pop const* a, Pop const* b) -> bool { - return sorted_fixed_map_less_than(a->get_issues(), b->get_issues()); + return sorted_fixed_map_less_than(a->get_issue_distribution(), b->get_issue_distribution()); }; case SORT_UNEMPLOYMENT: return [](Pop const* a, Pop const* b) -> bool { @@ -684,8 +684,8 @@ TypedArray MenuSingleton::get_population_menu_pop_rows(int32_t start } pop_dict[pop_militancy_key] = pop->get_militancy().to_float(); pop_dict[pop_consciousness_key] = pop->get_consciousness().to_float(); - pop_dict[pop_ideology_key] = GFXPieChartTexture::distribution_to_slices_array(pop->get_ideologies()); - pop_dict[pop_issues_key] = GFXPieChartTexture::distribution_to_slices_array(pop->get_issues()); + pop_dict[pop_ideology_key] = GFXPieChartTexture::distribution_to_slices_array(pop->get_ideology_distribution()); + pop_dict[pop_issues_key] = GFXPieChartTexture::distribution_to_slices_array(pop->get_issue_distribution()); pop_dict[pop_unemployment_key] = pop->get_unemployment().to_float(); pop_dict[pop_cash_key] = pop->get_cash().to_float(); pop_dict[pop_life_needs_key] = pop->get_life_needs_fulfilled().to_float();