Skip to content

Commit

Permalink
Merge branch 'main' into mbuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
wxwisiasdf authored Jan 7, 2024
2 parents 03d2ff3 + 118813e commit 40eccd0
Show file tree
Hide file tree
Showing 19 changed files with 364 additions and 58 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ target_include_directories(AliceCommon INTERFACE
${PROJECT_SOURCE_DIR}/src/gui/topbar_subwindows/production_subwindows
${PROJECT_SOURCE_DIR}/src/gui/topbar_subwindows/politics_subwindows
${PROJECT_SOURCE_DIR}/src/gui/topbar_subwindows/military_subwindows
${PROJECT_SOURCE_DIR}/src/ogl
${PROJECT_SOURCE_DIR}/src/graphics
${PROJECT_SOURCE_DIR}/src/parsing
${PROJECT_SOURCE_DIR}/src/window
${PROJECT_SOURCE_DIR}/src/text
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Join us on [discord](https://discord.gg/QUJExr4mRn) or visit our [documentation
- Mods may or may not run with more or less problems (see the October update and the compatibility patches channel in the discord for more information about particular mods).

## Contributing
- Please, [visit this page](https://schombert.github.io/Project-Alice/md_contributing.html) ([简中](https://github.com/schombert/Project-Alice/blob/main/docs/zh-cn/contributing.md),[Español](https://github.com/schombert/Project-Alice/blob/main/docs/es-es/contributing.md) [Português](https://github.com/schombert/Project-Alice/blob/main/docs/pt/contributing.md))
- Please, [visit this page](https://schombert.github.io/Project-Alice/md_contributing.html) ([简中](https://github.com/schombert/Project-Alice/blob/main/docs/zh-cn/contributing.md), [Español](https://github.com/schombert/Project-Alice/blob/main/docs/es-es/contributing.md), [Português](https://github.com/schombert/Project-Alice/blob/main/docs/pt/contributing.md))

## Updates

Expand Down
81 changes: 81 additions & 0 deletions docs/economy_design_es.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Diseño de la Economía

Este documento proporciona una descripción general del diseño de cómo se implementará la economía 1.0. La economía 1.0 no es una réplica exacta de la economía de Victoria 2. Está diseñada para ser una aproximación cercana, pero se han realizado algunas modificaciones para mejorar el rendimiento. Sustancialmente, esto significa que intentamos almacenar la menor cantidad de información posible y realizar la menor cantidad de pasadas sobre los datos. Desafortunadamente, incluso una aproximación cercana requiere una secuenciación sustancial, y hay poca posibilidad de paralelismo. Lo mejor que podamos lograr es hacer que la economía sea lo más autosuficiente posible para que la actualización del resto del día pueda ejecutarse junto a ella.

## Términos

Rentabilidad virtual: qué tan rentable sería una unidad estandarizada de producción *si* todos los insumos estuvieran disponibles, con los bonos de los trabajadores como si tuvieran empleo completo. (Teniendo en cuenta la fracción de producción vendida el día anterior en comparación con la producción real)

Escala de producción: la producción del productor se reducirá por dos factores: primero, por la disponibilidad de insumos. La escala efectiva de producción está limitada por la disponibilidad de insumos (y la escala real de producción se reducirá para cumplir con este valor). Cuando la oferta es mayor que la demanda real: la escala de producción disminuye a cierta tasa (por determinar, probablemente hasta cierta cantidad mínima, no hasta 0). Cuando la oferta es menor que la demanda real: la escala de producción aumenta a cierta tasa. Es posible que necesitemos un segundo factor de derivada aquí para reducir las fluctuaciones, ya que este es un segundo mecanismo de retroalimentación que empuja en la misma dirección que los movimientos de precios.

Cerrado: una fábrica con una escala de producción lo suficientemente baja está cerrada. Los artesanos con una escala de producción lo suficientemente baja cambiarán la producción, incluso si es nominalmente rentable (ya que esto significa que tienen problemas de disponibilidad de insumos).

## Actualización diaria

Iteramos sobre las naciones, en orden de rango.

### Estado inicial de la oferta nacional y global

El estado inicial de la oferta nacional se basa en lo que se produjo internamente, y la oferta global es lo que se produjo internamente el día anterior y no se consumió. Para el resto de este documento, tomamos la oferta nacional como "oferta nacional, existencias nacionales si la compra está habilitada, y lo que queda en la oferta nacional del líder de la esfera", que emula el comportamiento de Victoria 2.

Al comenzar el día, trasladamos la producción, de manera fraccional, al grupo de producción nacional del líder de la esfera, siguiendo la misma lógica que Victoria 2.

#### Datos requeridos:

Producción por nación (= pool de mercado nacional) para el día N - 1

### Calcular precios efectivos

El problema de los dos precios:

Para calcular la demanda y distribuir lo que está disponible de manera uniforme entre los consumidores de la nación, necesitamos saber cuáles son los precios para determinar cuánto es posible que un consumidor compre dada una renta particular (y cuál sería su renta suponiendo que podrían vender su producción). El problema es que los aranceles, etc., hacen que la compra desde el grupo global sea más cara. Esencialmente, hay dos precios, y la parte que puedes comprar localmente puede ser más barata (o más cara, en el caso de los subsidios) que el bien en el mercado global. Y esto significa que el costo efectivo depende de cuánto se compre en total, lo que a su vez depende del costo...

Victoria 2 resuelve esto ordenando a los consumidores de manera arbitraria. Hacen compras en orden, cada uno comprando de la oferta nacional (sí, incluso si es más barato comprar de la oferta global) hasta que se agota, y luego el resto debe lidiar con el precio de la oferta global. Esto no es ideal si esos precios divergen significativamente, porque significa que algunas cosas pueden ser o no rentables según donde caigan en este orden arbitrario.

Resolveremos este problema de la siguiente manera: usaremos la demanda real del *día anterior* para determinar cuánta de la compra se realizará desde las ofertas nacionales y globales (es decir, qué porcentaje se pudo hacer desde el grupo más barato). Usaremos eso para calcular un precio efectivo. Y luego, al final del día actual, veremos cuánto de esa compra provino realmente de cada grupo, etc. Dependiendo de la estabilidad de la simulación, en lugar de tomar el día anterior, podríamos construir este valor de manera iterativa como una combinación lineal del nuevo día y el día anterior.

(Si quisiéramos ser *más* realistas que Victoria 2, también podríamos calcular un segundo precio de venta... pero ¿por qué deberíamos hacerlo, si el juego base no se molesta en hacerlo?).

#### Datos requeridos:

Demanda real por nación para el día N - 1. Búfer temporal de precio efectivo por comodidad.

### Determinar empleo

Los posibles empleados se distribuyen a las fábricas haciendo lo siguiente:

Ordenamos las fábricas por prioridad y luego por rentabilidad *virtual* (bueno, como detalle de implementación, es más fácil hacer una ordenación estable por rentabilidad y luego una ordenación estable por prioridad, con estabilidad en ambos casos garantizando que el orden permanezca igual en todas partes). Ninguna fábrica contrata a más trabajadores de los que su escala de producción del día anterior permitiría. El empleo solo se permite cambiar tanto en un día (por determinar).

Esto también se aplica a los RGO, aunque solo hay un objetivo para la distribución.

#### Datos requeridos:

Escala de producción por fábrica, escala de producción de RGO por provincia y artesano. Valores de empleo por fábrica y por provincia de RGO.

### La nación determina el consumo objetivo y real

Se calcula el consumo deseado para todas las fuentes (poblaciones, fábricas, artesanos, existencias nacionales, proyectos) según cuánto pueden comprar dado su dinero. Se supone que los artesanos y las fábricas toman prestado contra su beneficio esperado si serán rentables dados los precios efectivos actuales (es decir, si son virtualmente rentables, con los efectos de empleo tenidos en cuenta, y las fábr

icas también deben tener en cuenta un costo de entrada de mano de obra mínima para el beneficio esperado). Si lo son, intentan comprar tanto como puedan dadas las limitaciones de su escala de producción y los números de empleo (y si no, su escala de producción disminuye). Las poblaciones intentan comprar tanto como puedan (hasta su último ingreso). Las naciones... aquí tenemos un problema. Es bastante natural decir: tanto como puedan dado sus reservas. Esto significaría que las naciones nunca entrarían en deuda. ¿Es eso lo que queremos? (Quizás para la IA y como opción del jugador). En cualquier caso, esto nos da números de "demanda real".

A partir de esto, derivamos límites máximos en la escala de producción para fábricas / artesanos (pero estos números no serán completamente precisos: los límites en la disponibilidad del bien A pueden hacer que más de B esté disponible porque el proceso de producción que utiliza tanto A como B consumirá menos de B, dejando más de B disponible para un proceso de producción no limitado por A. Hay un algoritmo que puede resolver esto, es una forma de problema de optimización lineal, que es solucionable, pero es algo complicado). También reducimos la escala de todas las demás compras de la misma manera.

Con la escala de consumo calculada, restamos las mercancías de los diversos grupos de oferta comenzando con el más barato de global o nacional. Dentro de lo nacional, primero restamos de lo verdaderamente nacional, luego del líder de la esfera nacional restante, luego de las existencias nacionales (si están habilitadas).

#### Datos requeridos:

Grupo de oferta global. Ingresos del día anterior por población. Búfer temporal de mercancías por comodidad para determinar disponibilidad. Existencias nacionales.

### Efectos del consumo

Las mercancías producidas (fábricas, artesanos, RGO) se colocan en el grupo de oferta nacional para el próximo día. Se calculan las ganancias de fábricas y artesanos, y las ganancias de los RGO, y a partir de estos valores se calculan los ingresos para diversas poblaciones de empleados para el próximo día. Las compras de la población se utilizan para calcular la satisfacción de necesidades, que no es un resultado directo de cuánto se consume, sino más bien una combinación lineal de la satisfacción anterior, que simula el ahorro de la población.

Cualquier oferta nacional restante se traslada al grupo global para el próximo día.

### Fin del día

La oferta real frente a la demanda real hace que los precios se ajusten. Cualquier oferta restante en el grupo global se elimina. Calculamos cuánto de la producción total mundial fue comprada, ya que esto afectará el precio de venta efectivo para el próximo día.

#### Datos requeridos:

Valores de producción global, valores de consumo real (o tal vez solo la fracción).
2 changes: 1 addition & 1 deletion src/ai/ai.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ float estimate_additional_offensive_strength(sys::state& state, dcon::nation_id
if(other.get_overlord_as_subject().get_ruler() != n && military::can_use_cb_against(state, other, target) && !military::has_truce_with(state, other, target))
value += estimate_strength(state, other);
}
return value;
return value * state.defines.alice_ai_offensive_strength_overestimate;
}

void update_ai_general_status(sys::state& state) {
Expand Down
8 changes: 4 additions & 4 deletions src/culture/rebels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -789,8 +789,8 @@ void sort_hunting_targets(sys::state& state, dcon::army_id ar, std::vector<dcon:
auto our_str = ai::estimate_army_strength(state, ar);
auto loc = state.world.army_get_location_from_army_location(ar);
std::sort(rebel_provs.begin(), rebel_provs.end(), [&](dcon::province_id a, dcon::province_id b) {
auto aa = 0.02f * -(our_str - ai::estimate_rebel_strength(state, a));
auto ab = 0.02f * -(our_str - ai::estimate_rebel_strength(state, b));
auto aa = 0.001f * -(our_str - ai::estimate_rebel_strength(state, a));
auto ab = 0.001f * -(our_str - ai::estimate_rebel_strength(state, b));
auto da = province::sorting_distance(state, a, loc) + aa;
auto db = province::sorting_distance(state, b, loc) + ab;
if(da != db)
Expand Down Expand Up @@ -831,8 +831,8 @@ void rebel_hunting_check(sys::state& state) {
std::sort(rebel_hunters.begin(), rebel_hunters.end(), [&](dcon::army_id a, dcon::army_id b) {
auto pa = state.world.army_get_location_from_army_location(a);
auto pb = state.world.army_get_location_from_army_location(b);
auto as = 0.02f * std::max<float>(ai::estimate_army_strength(state, a), 1.f);
auto bs = 0.02f * std::max<float>(ai::estimate_army_strength(state, b), 1.f);
auto as = 0.001f * std::max<float>(ai::estimate_army_strength(state, a), 1.f);
auto bs = 0.001f * std::max<float>(ai::estimate_army_strength(state, b), 1.f);
auto da = province::sorting_distance(state, pa, closest_prov) + as;
auto db = province::sorting_distance(state, pb, closest_prov) + bs;
if(da != db)
Expand Down
5 changes: 5 additions & 0 deletions src/gamestate/system_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "simple_fs.hpp"
#include "text.hpp"
#include "opengl_wrapper.hpp"
#include "directx_wrapper.hpp"
#include "fonts.hpp"
#include "sound.hpp"
#include "map_state.hpp"
Expand Down Expand Up @@ -596,6 +597,10 @@ struct alignas(64) state {
// graphics data
ogl::data open_gl;

#ifdef DIRECTX_11
directx::data directx;
#endif

// cheat data
cheat_data_s cheat_data;

Expand Down
File renamed without changes.
186 changes: 186 additions & 0 deletions src/graphics/directx_wrapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#include "directx_wrapper.hpp"
#include <d3dcompiler.h>


namespace directx {

void create_directx_context(sys::state& state) {
ID3D11Device* device;
ID3D11DeviceContext* context;

D3D_FEATURE_LEVEL feature_levels[] = {
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};

UINT flags = 0;
#ifdef _DEBUG
flags = D3D11_CREATE_DEVICE_DEBUG;
#endif

HRESULT result = D3D11CreateDevice(0, D3D_DRIVER_TYPE_HARDWARE, 0,
flags, feature_levels,
ARRAYSIZE(feature_levels),
D3D11_SDK_VERSION, &device, 0,
&context);


if(FAILED(result)) {
MessageBox(nullptr, L"Failed to create DirectX 11 device", 0, 0);
std::abort();
}
state.directx.device = device;
state.directx.context = context;

// Initializing DirectXTex
result = CoInitializeEx(nullptr, COINITBASE_MULTITHREADED);

if(FAILED(result)) {
std::abort();
}


}

void shutdown_directx(sys::state& state) {
state.directx.device->Release();
state.directx.context->Release();
}

/*
file_name: the path to the shader file
entry_point: the name of the function that acts as entry point for the shader
blob: the resulting compiled shader
*/
HRESULT compile_shader_from_file(sys::state& state, _In_ LPCWSTR file_name, _In_ LPCSTR entry_point, _Outptr_ ID3DBlob** blob) {
// Getting higher cs shader profile when possible
LPCSTR profile = (state.directx.device->GetFeatureLevel() >= D3D_FEATURE_LEVEL_11_0) ? "cs_5_0" : "cs_4_0";

// TODO: define required macros
const D3D_SHADER_MACRO defines[] =
{
NULL, NULL
};

UINT flags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
flags |= D3DCOMPILE_DEBUG;
#endif

ID3DBlob* shader_blob = nullptr;
ID3DBlob* error_blob = nullptr;

HRESULT result = D3DCompileFromFile(file_name, defines, D3D_COMPILE_STANDARD_FILE_INCLUDE, entry_point, profile,
flags, 0, &shader_blob, &error_blob);

if(FAILED(result)) {
if(error_blob) {
MessageBox(state.win_ptr->hwnd, L"An error has occurred during shader compilation", L"Shader compilation error", MB_OK);
error_blob->Release();
}

if(shader_blob)
shader_blob->Release();

return result;
}

*blob = shader_blob;
return result;
}
// TODO
void create_program();

// to load a single special icon
HRESULT load_dds_from_file_content(IWICImagingFactory* iwici_factory, IWICStream* iwici_stream, simple_fs::file_contents content, IWICBitmapDecoder* decoder) {

auto image_stream = const_cast<BYTE*>(reinterpret_cast<BYTE const*>(content.data));

HRESULT result = iwici_stream->InitializeFromMemory(image_stream, content.file_size);

if(FAILED(result)) {
return result;
}

result = iwici_factory->CreateDecoderFromStream(iwici_stream, NULL, WICDecodeMetadataCacheOnLoad, &decoder);
return result;
}

// to load them all
void load_special_icons(sys::state& state) {
HRESULT result;

IWICImagingFactory* iwici_factory;
IWICStream* iwici_stream = NULL;

result = CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&iwici_factory)
);

if(FAILED(result)) {
// TODO
}

result = iwici_factory->CreateStream(&iwici_stream);

if(FAILED(result)) {
// TODO
}

auto root = get_root(state.common_fs);
auto gfx_dir = simple_fs::open_directory(root, NATIVE("gfx"));

auto interface_dir = simple_fs::open_directory(gfx_dir, NATIVE("interface"));
auto money_dds = simple_fs::open_file(interface_dir, NATIVE("icon_money_big.dds"));
if(money_dds) {
auto content = simple_fs::view_contents(*money_dds);
result = load_dds_from_file_content(iwici_factory, iwici_stream, content, state.directx.money_icon_decoder);
if(FAILED(result)) {
// TODO
}
}

auto n_dds = simple_fs::open_file(interface_dir, NATIVE("politics_foreign_naval_units.dds"));
if(n_dds) {
auto content = simple_fs::view_contents(*n_dds);
result = load_dds_from_file_content(iwici_factory, iwici_stream, content, state.directx.navy_icon_decoder);
if(FAILED(result)) {
// TODO
}
}

auto a_dds = simple_fs::open_file(interface_dir, NATIVE("topbar_army.dds"));
if(a_dds) {
auto content = simple_fs::view_contents(*a_dds);
result = load_dds_from_file_content(iwici_factory, iwici_stream, content, state.directx.army_icon_decoder);
if(FAILED(result)) {
// TODO
}
}


auto assets_dir = simple_fs::open_directory(root, NATIVE("assets"));
auto cross_dds = simple_fs::open_file(assets_dir, NATIVE("trigger_not.dds"));
if(cross_dds) {
auto content = simple_fs::view_contents(*cross_dds);
result = load_dds_from_file_content(iwici_factory, iwici_stream, content, state.directx.cross_icon_decoder);
if(FAILED(result)) {
// TODO
}
}

auto checkmark_dds = simple_fs::open_file(assets_dir, NATIVE("trigger_yes.dds"));
if(checkmark_dds) {
auto content = simple_fs::view_contents(*checkmark_dds);
result = load_dds_from_file_content(iwici_factory, iwici_stream, content, state.directx.checkmark_icon_decoder);
if(FAILED(result)) {
// TODO
}
}
}
}
25 changes: 25 additions & 0 deletions src/graphics/directx_wrapper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#ifdef _WIN64
#define DIRECTX_11

#include <d3d11.h>
#include <wincodec.h>

namespace directx {
struct data {
ID3D11Device* device;
ID3D11DeviceContext* context;

IWICBitmapDecoder* money_icon_decoder;
IWICBitmapDecoder* navy_icon_decoder;
IWICBitmapDecoder* army_icon_decoder;
IWICBitmapDecoder* cross_icon_decoder;
IWICBitmapDecoder* checkmark_icon_decoder;

};

void create_directx_context(sys::state& state);
void shutdown_directx(sys::state& state);
}
#endif
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 40eccd0

Please sign in to comment.