World microapi
Some checks failed
Deploy Promiscuity Auth API / deploy (push) Successful in 49s
Deploy Promiscuity Character API / deploy (push) Successful in 46s
Deploy Promiscuity Crafting API / deploy (push) Successful in 47s
Deploy Promiscuity Inventory API / deploy (push) Successful in 47s
Deploy Promiscuity Locations API / deploy (push) Successful in 48s
Deploy Promiscuity Mail API / deploy (push) Successful in 46s
k8s smoke test / test (push) Has been cancelled
Some checks failed
Deploy Promiscuity Auth API / deploy (push) Successful in 49s
Deploy Promiscuity Character API / deploy (push) Successful in 46s
Deploy Promiscuity Crafting API / deploy (push) Successful in 47s
Deploy Promiscuity Inventory API / deploy (push) Successful in 47s
Deploy Promiscuity Locations API / deploy (push) Successful in 48s
Deploy Promiscuity Mail API / deploy (push) Successful in 46s
k8s smoke test / test (push) Has been cancelled
This commit is contained in:
parent
94473ab1b0
commit
2bed6aae4f
@ -4,11 +4,13 @@ const CHARACTER_API_URL := "https://pchar.ranaze.com/api/Characters"
|
|||||||
const LOCATION_API_URL := "https://ploc.ranaze.com/api/Locations"
|
const LOCATION_API_URL := "https://ploc.ranaze.com/api/Locations"
|
||||||
const INVENTORY_API_URL := "https://pinv.ranaze.com/api/inventory"
|
const INVENTORY_API_URL := "https://pinv.ranaze.com/api/inventory"
|
||||||
const MAIL_API_URL := "https://pmail.ranaze.com/api/mail"
|
const MAIL_API_URL := "https://pmail.ranaze.com/api/mail"
|
||||||
|
const WORLD_API_URL := "https://pworld.ranaze.com/api/world"
|
||||||
const START_SCREEN_SCENE := "res://scenes/UI/start_screen.tscn"
|
const START_SCREEN_SCENE := "res://scenes/UI/start_screen.tscn"
|
||||||
const SETTINGS_SCENE := "res://scenes/UI/Settings.tscn"
|
const SETTINGS_SCENE := "res://scenes/UI/Settings.tscn"
|
||||||
const CHARACTER_SLOT_COUNT := 6
|
const CHARACTER_SLOT_COUNT := 6
|
||||||
const VISIBLE_CHARACTERS_REFRESH_INTERVAL := 5.0
|
const VISIBLE_CHARACTERS_REFRESH_INTERVAL := 5.0
|
||||||
const HEARTBEAT_INTERVAL := 10.0
|
const HEARTBEAT_INTERVAL := 10.0
|
||||||
|
const WORLD_CYCLE_REFRESH_INTERVAL := 15.0
|
||||||
|
|
||||||
@export var tile_size := 8.0
|
@export var tile_size := 8.0
|
||||||
@export var block_height := 1.0
|
@export var block_height := 1.0
|
||||||
@ -77,6 +79,9 @@ var _mail_sent: Array = []
|
|||||||
var _mail_request_in_flight := false
|
var _mail_request_in_flight := false
|
||||||
var _selected_inbox_mail_id := ""
|
var _selected_inbox_mail_id := ""
|
||||||
var _selected_sent_mail_id := ""
|
var _selected_sent_mail_id := ""
|
||||||
|
var _world_cycle_request_in_flight := false
|
||||||
|
var _world_cycle_refresh_elapsed := 0.0
|
||||||
|
var _world_cycle: Dictionary = {}
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
@ -102,6 +107,7 @@ func _ready() -> void:
|
|||||||
_block.visible = false
|
_block.visible = false
|
||||||
_deactivate_player_for_load()
|
_deactivate_player_for_load()
|
||||||
await _load_existing_locations()
|
await _load_existing_locations()
|
||||||
|
_refresh_world_cycle()
|
||||||
_refresh_visible_characters()
|
_refresh_visible_characters()
|
||||||
_ensure_selected_location_exists(_center_coord)
|
_ensure_selected_location_exists(_center_coord)
|
||||||
_rebuild_tiles(_center_coord)
|
_rebuild_tiles(_center_coord)
|
||||||
@ -114,12 +120,16 @@ func _process(_delta: float) -> void:
|
|||||||
return
|
return
|
||||||
_visible_character_refresh_elapsed += _delta
|
_visible_character_refresh_elapsed += _delta
|
||||||
_heartbeat_elapsed += _delta
|
_heartbeat_elapsed += _delta
|
||||||
|
_world_cycle_refresh_elapsed += _delta
|
||||||
if _visible_character_refresh_elapsed >= VISIBLE_CHARACTERS_REFRESH_INTERVAL:
|
if _visible_character_refresh_elapsed >= VISIBLE_CHARACTERS_REFRESH_INTERVAL:
|
||||||
_visible_character_refresh_elapsed = 0.0
|
_visible_character_refresh_elapsed = 0.0
|
||||||
_refresh_visible_characters()
|
_refresh_visible_characters()
|
||||||
if _heartbeat_elapsed >= HEARTBEAT_INTERVAL:
|
if _heartbeat_elapsed >= HEARTBEAT_INTERVAL:
|
||||||
_heartbeat_elapsed = 0.0
|
_heartbeat_elapsed = 0.0
|
||||||
_send_presence_heartbeat()
|
_send_presence_heartbeat()
|
||||||
|
if _world_cycle_refresh_elapsed >= WORLD_CYCLE_REFRESH_INTERVAL:
|
||||||
|
_world_cycle_refresh_elapsed = 0.0
|
||||||
|
_refresh_world_cycle()
|
||||||
if _inventory_menu.visible or _mail_menu.visible:
|
if _inventory_menu.visible or _mail_menu.visible:
|
||||||
return
|
return
|
||||||
var target_world_pos := _get_stream_position()
|
var target_world_pos := _get_stream_position()
|
||||||
@ -1325,6 +1335,50 @@ func _refresh_visible_locations_async() -> void:
|
|||||||
await _load_existing_locations()
|
await _load_existing_locations()
|
||||||
|
|
||||||
|
|
||||||
|
func _refresh_world_cycle() -> void:
|
||||||
|
if _world_cycle_request_in_flight:
|
||||||
|
return
|
||||||
|
_refresh_world_cycle_async()
|
||||||
|
|
||||||
|
|
||||||
|
func _refresh_world_cycle_async() -> void:
|
||||||
|
_world_cycle_request_in_flight = true
|
||||||
|
|
||||||
|
var request := HTTPRequest.new()
|
||||||
|
add_child(request)
|
||||||
|
|
||||||
|
var headers := PackedStringArray()
|
||||||
|
if not AuthState.access_token.is_empty():
|
||||||
|
headers.append("Authorization: Bearer %s" % AuthState.access_token)
|
||||||
|
|
||||||
|
var err := request.request("%s/cycle" % WORLD_API_URL, headers, HTTPClient.METHOD_GET)
|
||||||
|
if err != OK:
|
||||||
|
push_warning("Failed to request world cycle: %s" % err)
|
||||||
|
request.queue_free()
|
||||||
|
_world_cycle_request_in_flight = false
|
||||||
|
return
|
||||||
|
|
||||||
|
var result: Array = await request.request_completed
|
||||||
|
request.queue_free()
|
||||||
|
|
||||||
|
var result_code: int = result[0]
|
||||||
|
var response_code: int = result[1]
|
||||||
|
var response_body: String = result[3].get_string_from_utf8()
|
||||||
|
if result_code != HTTPRequest.RESULT_SUCCESS or response_code < 200 or response_code >= 300:
|
||||||
|
push_warning("Failed to load world cycle (%s/%s): %s" % [result_code, response_code, response_body])
|
||||||
|
_world_cycle_request_in_flight = false
|
||||||
|
return
|
||||||
|
|
||||||
|
var parsed: Variant = JSON.parse_string(response_body)
|
||||||
|
if typeof(parsed) != TYPE_DICTIONARY:
|
||||||
|
push_warning("World cycle response was not an object.")
|
||||||
|
_world_cycle_request_in_flight = false
|
||||||
|
return
|
||||||
|
|
||||||
|
_world_cycle = parsed as Dictionary
|
||||||
|
_world_cycle_request_in_flight = false
|
||||||
|
|
||||||
|
|
||||||
func _try_interact_current_tile() -> void:
|
func _try_interact_current_tile() -> void:
|
||||||
if _interact_in_flight:
|
if _interact_in_flight:
|
||||||
return
|
return
|
||||||
|
|||||||
24
microservices/WorldApi/Controllers/WorldController.cs
Normal file
24
microservices/WorldApi/Controllers/WorldController.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using WorldApi.Services;
|
||||||
|
|
||||||
|
namespace WorldApi.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class WorldController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly WorldCycleService _worldCycle;
|
||||||
|
|
||||||
|
public WorldController(WorldCycleService worldCycle)
|
||||||
|
{
|
||||||
|
_worldCycle = worldCycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("cycle")]
|
||||||
|
[Authorize(Roles = "USER,SUPER")]
|
||||||
|
public IActionResult GetCycle()
|
||||||
|
{
|
||||||
|
return Ok(_worldCycle.GetCurrentCycle());
|
||||||
|
}
|
||||||
|
}
|
||||||
15
microservices/WorldApi/DOCUMENTS.md
Normal file
15
microservices/WorldApi/DOCUMENTS.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# WorldApi document shapes
|
||||||
|
|
||||||
|
Outbound JSON documents
|
||||||
|
- WorldCycleResponse (`GET /api/world/cycle`)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"currentUtc": "string (ISO-8601 datetime)",
|
||||||
|
"dayLengthSeconds": 1200,
|
||||||
|
"timeOfDaySeconds": 438.2,
|
||||||
|
"timeOfDayNormalized": 0.365,
|
||||||
|
"phase": "day",
|
||||||
|
"isDay": true,
|
||||||
|
"lightLevel": 0.91
|
||||||
|
}
|
||||||
|
```
|
||||||
18
microservices/WorldApi/Models/WorldCycleResponse.cs
Normal file
18
microservices/WorldApi/Models/WorldCycleResponse.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
namespace WorldApi.Models;
|
||||||
|
|
||||||
|
public class WorldCycleResponse
|
||||||
|
{
|
||||||
|
public DateTime CurrentUtc { get; set; }
|
||||||
|
|
||||||
|
public double DayLengthSeconds { get; set; }
|
||||||
|
|
||||||
|
public double TimeOfDaySeconds { get; set; }
|
||||||
|
|
||||||
|
public double TimeOfDayNormalized { get; set; }
|
||||||
|
|
||||||
|
public string Phase { get; set; } = "day";
|
||||||
|
|
||||||
|
public bool IsDay { get; set; }
|
||||||
|
|
||||||
|
public double LightLevel { get; set; }
|
||||||
|
}
|
||||||
106
microservices/WorldApi/Program.cs
Normal file
106
microservices/WorldApi/Program.cs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Diagnostics;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using System.Text;
|
||||||
|
using WorldApi.Services;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
builder.Services.AddControllers();
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<WorldCycleService>();
|
||||||
|
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddSwaggerGen(c =>
|
||||||
|
{
|
||||||
|
c.SwaggerDoc("v1", new OpenApiInfo { Title = "World API", Version = "v1" });
|
||||||
|
c.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Type = SecuritySchemeType.Http,
|
||||||
|
Scheme = "bearer",
|
||||||
|
BearerFormat = "JWT",
|
||||||
|
Description = "Paste your access token here (no 'Bearer ' prefix needed)."
|
||||||
|
});
|
||||||
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||||
|
{
|
||||||
|
{
|
||||||
|
new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference
|
||||||
|
{ Type = ReferenceType.SecurityScheme, Id = "bearerAuth" }
|
||||||
|
},
|
||||||
|
Array.Empty<string>()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var cfg = builder.Configuration;
|
||||||
|
var jwtKey = cfg["Jwt:Key"] ?? throw new Exception("Jwt:Key missing");
|
||||||
|
var issuer = cfg["Jwt:Issuer"] ?? "promiscuity";
|
||||||
|
var aud = cfg["Jwt:Audience"] ?? issuer;
|
||||||
|
|
||||||
|
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
|
.AddJwtBearer(o =>
|
||||||
|
{
|
||||||
|
o.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidIssuer = issuer,
|
||||||
|
ValidateAudience = true,
|
||||||
|
ValidAudience = aud,
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey)),
|
||||||
|
ValidateLifetime = true,
|
||||||
|
ClockSkew = TimeSpan.FromSeconds(30)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddAuthorization();
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
app.UseExceptionHandler(errorApp =>
|
||||||
|
{
|
||||||
|
errorApp.Run(async context =>
|
||||||
|
{
|
||||||
|
var feature = context.Features.Get<IExceptionHandlerFeature>();
|
||||||
|
var exception = feature?.Error;
|
||||||
|
var logger = context.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger("GlobalException");
|
||||||
|
var traceId = context.TraceIdentifier;
|
||||||
|
|
||||||
|
if (exception is not null)
|
||||||
|
{
|
||||||
|
logger.LogError(
|
||||||
|
exception,
|
||||||
|
"Unhandled exception for {Method} {Path}. TraceId={TraceId}",
|
||||||
|
context.Request.Method,
|
||||||
|
context.Request.Path,
|
||||||
|
traceId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
||||||
|
context.Response.ContentType = "application/problem+json";
|
||||||
|
|
||||||
|
await context.Response.WriteAsJsonAsync(new
|
||||||
|
{
|
||||||
|
type = "https://httpstatuses.com/500",
|
||||||
|
title = "Internal Server Error",
|
||||||
|
status = 500,
|
||||||
|
detail = exception?.Message ?? "An unexpected server error occurred.",
|
||||||
|
traceId
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapGet("/healthz", () => Results.Ok("ok"));
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI(o =>
|
||||||
|
{
|
||||||
|
o.SwaggerEndpoint("/swagger/v1/swagger.json", "World API v1");
|
||||||
|
o.RoutePrefix = "swagger";
|
||||||
|
});
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
app.MapControllers();
|
||||||
|
app.Run();
|
||||||
14
microservices/WorldApi/Properties/launchSettings.json
Normal file
14
microservices/WorldApi/Properties/launchSettings.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"applicationUrl": "http://localhost:5185",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
microservices/WorldApi/README.md
Normal file
3
microservices/WorldApi/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# WorldApi
|
||||||
|
|
||||||
|
Global world simulation state such as the shared day/night cycle.
|
||||||
56
microservices/WorldApi/Services/WorldCycleService.cs
Normal file
56
microservices/WorldApi/Services/WorldCycleService.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
using WorldApi.Models;
|
||||||
|
|
||||||
|
namespace WorldApi.Services;
|
||||||
|
|
||||||
|
public class WorldCycleService
|
||||||
|
{
|
||||||
|
private readonly double _dayLengthSeconds;
|
||||||
|
private readonly DateTime _epochUtc;
|
||||||
|
|
||||||
|
public WorldCycleService(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
_dayLengthSeconds = Math.Max(1.0, configuration.GetValue<double?>("WorldCycle:DayLengthSeconds") ?? 1200.0);
|
||||||
|
|
||||||
|
var configuredEpoch = configuration["WorldCycle:EpochUtc"];
|
||||||
|
_epochUtc = DateTime.TryParse(
|
||||||
|
configuredEpoch,
|
||||||
|
null,
|
||||||
|
System.Globalization.DateTimeStyles.AdjustToUniversal | System.Globalization.DateTimeStyles.AssumeUniversal,
|
||||||
|
out var parsedEpoch)
|
||||||
|
? parsedEpoch
|
||||||
|
: new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorldCycleResponse GetCurrentCycle()
|
||||||
|
{
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
var elapsedSeconds = Math.Max(0.0, (now - _epochUtc).TotalSeconds);
|
||||||
|
var timeOfDaySeconds = elapsedSeconds % _dayLengthSeconds;
|
||||||
|
var normalized = timeOfDaySeconds / _dayLengthSeconds;
|
||||||
|
var solarCurve = Math.Sin(normalized * Math.PI);
|
||||||
|
var lightLevel = Math.Clamp(solarCurve, 0.0, 1.0);
|
||||||
|
|
||||||
|
return new WorldCycleResponse
|
||||||
|
{
|
||||||
|
CurrentUtc = now,
|
||||||
|
DayLengthSeconds = _dayLengthSeconds,
|
||||||
|
TimeOfDaySeconds = timeOfDaySeconds,
|
||||||
|
TimeOfDayNormalized = normalized,
|
||||||
|
Phase = ResolvePhase(normalized),
|
||||||
|
IsDay = lightLevel > 0.0,
|
||||||
|
LightLevel = lightLevel
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ResolvePhase(double normalized)
|
||||||
|
{
|
||||||
|
return normalized switch
|
||||||
|
{
|
||||||
|
< 0.20 => "night",
|
||||||
|
< 0.30 => "dawn",
|
||||||
|
< 0.70 => "day",
|
||||||
|
< 0.80 => "dusk",
|
||||||
|
_ => "night"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
15
microservices/WorldApi/WorldApi.csproj
Normal file
15
microservices/WorldApi/WorldApi.csproj
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.8" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.8" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
8
microservices/WorldApi/appsettings.Development.json
Normal file
8
microservices/WorldApi/appsettings.Development.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
microservices/WorldApi/appsettings.json
Normal file
7
microservices/WorldApi/appsettings.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"Kestrel": { "Endpoints": { "Http": { "Url": "http://0.0.0.0:5004" } } },
|
||||||
|
"WorldCycle": { "DayLengthSeconds": 1200, "EpochUtc": "2026-01-01T00:00:00Z" },
|
||||||
|
"Jwt": { "Key": "SuperUltraSecureJwtKeyWithAtLeast32Chars!!", "Issuer": "promiscuity", "Audience": "promiscuity-auth-api" },
|
||||||
|
"Logging": { "LogLevel": { "Default": "Information" } },
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
@ -14,6 +14,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MailApi", "MailApi\MailApi.
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CraftingApi", "CraftingApi\CraftingApi.csproj", "{0B5EE564-C6E1-4BA7-B0E2-B86D363A9C74}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CraftingApi", "CraftingApi\CraftingApi.csproj", "{0B5EE564-C6E1-4BA7-B0E2-B86D363A9C74}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorldApi", "WorldApi\WorldApi.csproj", "{C8F20B54-2A76-4BE0-8DA8-E146D1AF4D10}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -44,6 +46,10 @@ Global
|
|||||||
{0B5EE564-C6E1-4BA7-B0E2-B86D363A9C74}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{0B5EE564-C6E1-4BA7-B0E2-B86D363A9C74}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{0B5EE564-C6E1-4BA7-B0E2-B86D363A9C74}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{0B5EE564-C6E1-4BA7-B0E2-B86D363A9C74}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{0B5EE564-C6E1-4BA7-B0E2-B86D363A9C74}.Release|Any CPU.Build.0 = Release|Any CPU
|
{0B5EE564-C6E1-4BA7-B0E2-B86D363A9C74}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C8F20B54-2A76-4BE0-8DA8-E146D1AF4D10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C8F20B54-2A76-4BE0-8DA8-E146D1AF4D10}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C8F20B54-2A76-4BE0-8DA8-E146D1AF4D10}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C8F20B54-2A76-4BE0-8DA8-E146D1AF4D10}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user