mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-18 18:11:24 +01:00
Merge branch 'master' of https://github.com/Azgaar/Fantasy-Map-Generator into submap-refactoring
This commit is contained in:
commit
b5661de19c
8 changed files with 176 additions and 101 deletions
34
index.html
34
index.html
|
|
@ -4964,29 +4964,21 @@
|
||||||
>Model:
|
>Model:
|
||||||
<select id="aiGeneratorModel"></select>
|
<select id="aiGeneratorModel"></select>
|
||||||
</label>
|
</label>
|
||||||
<label for="aiGeneratorTemperature"
|
<label
|
||||||
>Temperature:
|
for="aiGeneratorTemperature"
|
||||||
<input id="aiGeneratorTemperature" type="number" min="0" max="2" placeholder="1.2" class="icon-key" />
|
data-tip="Temperature controls response randomness; higher values mean more creativity, lower values mean more predictability"
|
||||||
<a
|
>
|
||||||
href="https://platform.openai.com/docs/api-reference/chat/create#chat-create-temperature"
|
Temperature:
|
||||||
target="_blank"
|
<input id="aiGeneratorTemperature" type="number" min="-1" max="2" step=".1" class="icon-key" />
|
||||||
rel="noreferrer"
|
|
||||||
class="icon-help-circled"
|
|
||||||
style="text-decoration: none"
|
|
||||||
data-tip="Between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic."
|
|
||||||
></a>
|
|
||||||
</label>
|
</label>
|
||||||
<label for="aiGeneratorKey"
|
<label for="aiGeneratorKey"
|
||||||
>Key:
|
>Key:
|
||||||
<input id="aiGeneratorKey" placeholder="Enter OpenAI API key" class="icon-key" />
|
<input id="aiGeneratorKey" placeholder="Enter API key" class="icon-key" />
|
||||||
<a
|
<button
|
||||||
href="https://platform.openai.com/account/api-keys"
|
id="aiGeneratorKeyHelp"
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
class="icon-help-circled"
|
class="icon-help-circled"
|
||||||
style="text-decoration: none"
|
data-tip="Open provider's website to get the API key there. Note: the Map Genenerator doesn't store the key or any generated data"
|
||||||
data-tip="Get the key at OpenAI website. The key will be stored in your browser and send to OpenAI API directly. The Map Genenerator doesn't store the key or any generated data"
|
/>
|
||||||
></a>
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -8098,7 +8090,7 @@
|
||||||
|
|
||||||
<script defer src="modules/relief-icons.js?v=1.99.05"></script>
|
<script defer src="modules/relief-icons.js?v=1.99.05"></script>
|
||||||
<script defer src="modules/ui/style.js?v=1.104.0"></script>
|
<script defer src="modules/ui/style.js?v=1.104.0"></script>
|
||||||
<script defer src="modules/ui/editors.js?v=1.105.11"></script>
|
<script defer src="modules/ui/editors.js?v=1.105.23"></script>
|
||||||
<script defer src="modules/ui/tools.js?v=1.105.13"></script>
|
<script defer src="modules/ui/tools.js?v=1.105.13"></script>
|
||||||
<script defer src="modules/ui/world-configurator.js?v=1.105.4"></script>
|
<script defer src="modules/ui/world-configurator.js?v=1.105.4"></script>
|
||||||
<script defer src="modules/ui/heightmap-editor.js?v=1.105.2"></script>
|
<script defer src="modules/ui/heightmap-editor.js?v=1.105.2"></script>
|
||||||
|
|
@ -8141,7 +8133,7 @@
|
||||||
<script defer src="libs/rgbquant.min.js"></script>
|
<script defer src="libs/rgbquant.min.js"></script>
|
||||||
<script defer src="libs/jquery.ui.touch-punch.min.js"></script>
|
<script defer src="libs/jquery.ui.touch-punch.min.js"></script>
|
||||||
<script defer src="modules/io/save.js?v=1.100.00"></script>
|
<script defer src="modules/io/save.js?v=1.100.00"></script>
|
||||||
<script defer src="modules/io/load.js?v=1.105.17"></script>
|
<script defer src="modules/io/load.js?v=1.105.24"></script>
|
||||||
<script defer src="modules/io/cloud.js?v=1.105.19"></script>
|
<script defer src="modules/io/cloud.js?v=1.105.19"></script>
|
||||||
<script defer src="modules/io/export.js?v=1.100.00"></script>
|
<script defer src="modules/io/export.js?v=1.100.00"></script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -972,5 +972,9 @@ export function resolveVersionConflicts(mapVersion) {
|
||||||
.attr("letter-spacing", null)
|
.attr("letter-spacing", null)
|
||||||
.attr("fill", null)
|
.attr("fill", null)
|
||||||
.attr("stroke", null);
|
.attr("stroke", null);
|
||||||
|
|
||||||
|
// pole can be missing for some states/provinces
|
||||||
|
BurgsAndStates.getPoles();
|
||||||
|
Provinces.getPoles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -345,10 +345,13 @@ function cultureChangeName() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function cultureRegenerateName() {
|
function cultureRegenerateName() {
|
||||||
const culture = +this.parentNode.dataset.id;
|
const cultureId = +this.parentNode.dataset.id;
|
||||||
const name = Names.getCultureShort(culture);
|
const base = pack.cultures[cultureId].base;
|
||||||
|
if (!nameBases[base]) return tip("Namesbase is not defined, please select a valid namesbase", false, "error", 5000);
|
||||||
|
|
||||||
|
const name = Names.getCultureShort(cultureId);
|
||||||
this.parentNode.querySelector("input.cultureName").value = name;
|
this.parentNode.querySelector("input.cultureName").value = name;
|
||||||
pack.cultures[culture].name = name;
|
pack.cultures[cultureId].name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cultureChangeExpansionism() {
|
function cultureChangeExpansionism() {
|
||||||
|
|
@ -494,12 +497,15 @@ function cultureRegenerateBurgs() {
|
||||||
if (customization === 4) return;
|
if (customization === 4) return;
|
||||||
|
|
||||||
const cultureId = +this.parentNode.dataset.id;
|
const cultureId = +this.parentNode.dataset.id;
|
||||||
const cBurgs = pack.burgs.filter(b => b.culture === cultureId && !b.lock);
|
const base = pack.cultures[cultureId].base;
|
||||||
cBurgs.forEach(b => {
|
if (!nameBases[base]) return tip("Namesbase is not defined, please select a valid namesbase", false, "error", 5000);
|
||||||
|
|
||||||
|
const cultureBurgs = pack.burgs.filter(b => b.culture === cultureId && !b.removed && !b.lock);
|
||||||
|
cultureBurgs.forEach(b => {
|
||||||
b.name = Names.getCulture(cultureId);
|
b.name = Names.getCulture(cultureId);
|
||||||
labels.select("[data-id='" + b.i + "']").text(b.name);
|
labels.select("[data-id='" + b.i + "']").text(b.name);
|
||||||
});
|
});
|
||||||
tip(`Names for ${cBurgs.length} burgs are regenerated`, false, "success");
|
tip(`Names for ${cultureBurgs.length} burgs are regenerated`, false, "success");
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeCulture(cultureId) {
|
function removeCulture(cultureId) {
|
||||||
|
|
@ -849,14 +855,15 @@ async function uploadCulturesData() {
|
||||||
this.value = "";
|
this.value = "";
|
||||||
const csv = await file.text();
|
const csv = await file.text();
|
||||||
const data = d3.csvParse(csv, d => ({
|
const data = d3.csvParse(csv, d => ({
|
||||||
i: +d.Id,
|
|
||||||
name: d.Name,
|
name: d.Name,
|
||||||
|
i: +d.Id,
|
||||||
color: d.Color,
|
color: d.Color,
|
||||||
expansionism: +d.Expansionism,
|
expansionism: +d.Expansionism,
|
||||||
type: d.Type,
|
type: d.Type,
|
||||||
population: +d.Population,
|
population: +d.Population,
|
||||||
emblemsShape: d["Emblems Shape"],
|
emblemsShape: d["Emblems Shape"],
|
||||||
origins: d.Origins
|
origins: d.Origins,
|
||||||
|
namesbase: d.Namesbase
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const {cultures, cells} = pack;
|
const {cultures, cells} = pack;
|
||||||
|
|
@ -883,7 +890,7 @@ async function uploadCulturesData() {
|
||||||
culture.i
|
culture.i
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
current = {i: cultures.length, center: ra(populated), area: 0, cells: 0, origin: 0, rural: 0, urban: 0};
|
current = {i: cultures.length, center: ra(populated), area: 0, cells: 0, origins: [0], rural: 0, urban: 0};
|
||||||
cultures.push(current);
|
cultures.push(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -903,6 +910,10 @@ async function uploadCulturesData() {
|
||||||
else current.type = "Generic";
|
else current.type = "Generic";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
culture.origins = current.i ? restoreOrigins(culture.origins || "") : [null];
|
||||||
|
current.shield = shapes.includes(culture.emblemsShape) ? culture.emblemsShape : "heater";
|
||||||
|
current.base = nameBases.findIndex(n => n.name == culture.namesbase); // can be -1 if namesbase is not found
|
||||||
|
|
||||||
function restoreOrigins(originsString) {
|
function restoreOrigins(originsString) {
|
||||||
const originNames = originsString
|
const originNames = originsString
|
||||||
.replaceAll('"', "")
|
.replaceAll('"', "")
|
||||||
|
|
@ -918,12 +929,6 @@ async function uploadCulturesData() {
|
||||||
current.origins = originIds.filter(id => id !== null);
|
current.origins = originIds.filter(id => id !== null);
|
||||||
if (!current.origins.length) current.origins = [0];
|
if (!current.origins.length) current.origins = [0];
|
||||||
}
|
}
|
||||||
|
|
||||||
culture.origins = current.i ? restoreOrigins(culture.origins || "") : [null];
|
|
||||||
current.shield = shapes.includes(culture.emblemsShape) ? culture.emblemsShape : "heater";
|
|
||||||
|
|
||||||
const nameBaseIndex = nameBases.findIndex(n => n.name == culture.namesbase);
|
|
||||||
current.base = nameBaseIndex === -1 ? 0 : nameBaseIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cultures.filter(c => c.removed).forEach(c => removeCulture(c.i));
|
cultures.filter(c => c.removed).forEach(c => removeCulture(c.i));
|
||||||
|
|
|
||||||
|
|
@ -583,4 +583,9 @@ James Benware
|
||||||
FortunesFaded
|
FortunesFaded
|
||||||
breadsticks
|
breadsticks
|
||||||
Murderbits
|
Murderbits
|
||||||
Ben Jones`;
|
Ben Jones
|
||||||
|
Marco Faltracco
|
||||||
|
L
|
||||||
|
silentArtifact
|
||||||
|
Keith Potter
|
||||||
|
Morgan Gilbert`;
|
||||||
|
|
|
||||||
|
|
@ -471,7 +471,7 @@ async function parseLoadedData(data, mapVersion) {
|
||||||
|
|
||||||
{
|
{
|
||||||
// dynamically import and run auto-update script
|
// dynamically import and run auto-update script
|
||||||
const {resolveVersionConflicts} = await import("../dynamic/auto-update.js?v=1.105.10");
|
const {resolveVersionConflicts} = await import("../dynamic/auto-update.js?v=1.105.24");
|
||||||
resolveVersionConflicts(mapVersion);
|
resolveVersionConflicts(mapVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,114 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const GPT_MODELS = ["gpt-4o-mini", "chatgpt-4o-latest", "gpt-4o", "gpt-4-turbo", "gpt-4", "gpt-3.5-turbo"];
|
const PROVIDERS = {
|
||||||
|
openai: {
|
||||||
|
keyLink: "https://platform.openai.com/account/api-keys",
|
||||||
|
generate: generateWithOpenAI
|
||||||
|
},
|
||||||
|
anthropic: {
|
||||||
|
keyLink: "https://console.anthropic.com/account/keys",
|
||||||
|
generate: generateWithAnthropic
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const DEFAULT_MODEL = "gpt-4o-mini";
|
||||||
|
|
||||||
|
const MODELS = {
|
||||||
|
"gpt-4o-mini": "openai",
|
||||||
|
"chatgpt-4o-latest": "openai",
|
||||||
|
"gpt-4o": "openai",
|
||||||
|
"gpt-4-turbo": "openai",
|
||||||
|
"o1-preview": "openai",
|
||||||
|
"o1-mini": "openai",
|
||||||
|
"claude-3-5-haiku-latest": "anthropic",
|
||||||
|
"claude-3-5-sonnet-latest": "anthropic",
|
||||||
|
"claude-3-opus-latest": "anthropic"
|
||||||
|
};
|
||||||
|
|
||||||
const SYSTEM_MESSAGE = "I'm working on my fantasy map.";
|
const SYSTEM_MESSAGE = "I'm working on my fantasy map.";
|
||||||
|
|
||||||
|
async function generateWithOpenAI({key, model, prompt, temperature, onContent}) {
|
||||||
|
const headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Bearer ${key}`
|
||||||
|
};
|
||||||
|
|
||||||
|
const messages = [
|
||||||
|
{role: "system", content: SYSTEM_MESSAGE},
|
||||||
|
{role: "user", content: prompt}
|
||||||
|
];
|
||||||
|
|
||||||
|
const response = await fetch("https://api.openai.com/v1/chat/completions", {
|
||||||
|
method: "POST",
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify({model, messages, temperature, stream: true})
|
||||||
|
});
|
||||||
|
|
||||||
|
const getContent = json => {
|
||||||
|
const content = json.choices?.[0]?.delta?.content;
|
||||||
|
if (content) onContent(content);
|
||||||
|
};
|
||||||
|
|
||||||
|
await handleStream(response, getContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateWithAnthropic({key, model, prompt, temperature, onContent}) {
|
||||||
|
const headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"x-api-key": key,
|
||||||
|
"anthropic-version": "2023-06-01",
|
||||||
|
"anthropic-dangerous-direct-browser-access": "true"
|
||||||
|
};
|
||||||
|
|
||||||
|
const messages = [{role: "user", content: prompt}];
|
||||||
|
|
||||||
|
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
||||||
|
method: "POST",
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify({model, system: SYSTEM_MESSAGE, messages, temperature, max_tokens: 4096, stream: true})
|
||||||
|
});
|
||||||
|
|
||||||
|
const getContent = json => {
|
||||||
|
const content = json.delta?.text;
|
||||||
|
if (content) onContent(content);
|
||||||
|
};
|
||||||
|
|
||||||
|
await handleStream(response, getContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleStream(response, getContent) {
|
||||||
|
if (!response.ok) {
|
||||||
|
const json = await response.json();
|
||||||
|
throw new Error(json?.error?.message || "Failed to generate");
|
||||||
|
}
|
||||||
|
|
||||||
|
const reader = response.body.getReader();
|
||||||
|
const decoder = new TextDecoder("utf-8");
|
||||||
|
let buffer = "";
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const {done, value} = await reader.read();
|
||||||
|
if (done) break;
|
||||||
|
|
||||||
|
buffer += decoder.decode(value, {stream: true});
|
||||||
|
const lines = buffer.split("\n");
|
||||||
|
|
||||||
|
for (let i = 0; i < lines.length - 1; i++) {
|
||||||
|
const line = lines[i].trim();
|
||||||
|
if (line.startsWith("data: ") && line !== "data: [DONE]") {
|
||||||
|
try {
|
||||||
|
const json = JSON.parse(line.slice(6));
|
||||||
|
getContent(json);
|
||||||
|
} catch (jsonError) {
|
||||||
|
ERROR && console.error(`Failed to parse JSON:`, jsonError, `Line: ${line}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = lines.at(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function generateWithAi(defaultPrompt, onApply) {
|
function generateWithAi(defaultPrompt, onApply) {
|
||||||
updateValues();
|
updateValues();
|
||||||
|
|
||||||
|
|
@ -29,90 +135,53 @@ function generateWithAi(defaultPrompt, onApply) {
|
||||||
if (modules.generateWithAi) return;
|
if (modules.generateWithAi) return;
|
||||||
modules.generateWithAi = true;
|
modules.generateWithAi = true;
|
||||||
|
|
||||||
|
byId("aiGeneratorKeyHelp").on("click", function (e) {
|
||||||
|
const model = byId("aiGeneratorModel").value;
|
||||||
|
const provider = MODELS[model];
|
||||||
|
openURL(PROVIDERS[provider].keyLink);
|
||||||
|
});
|
||||||
|
|
||||||
function updateValues() {
|
function updateValues() {
|
||||||
byId("aiGeneratorResult").value = "";
|
byId("aiGeneratorResult").value = "";
|
||||||
byId("aiGeneratorPrompt").value = defaultPrompt;
|
byId("aiGeneratorPrompt").value = defaultPrompt;
|
||||||
byId("aiGeneratorKey").value = localStorage.getItem("fmg-ai-kl") || "";
|
byId("aiGeneratorTemperature").value = localStorage.getItem("fmg-ai-temperature") || "1";
|
||||||
byId("aiGeneratorTemperature").value = localStorage.getItem("fmg-ai-temperature") || "1.2";
|
|
||||||
|
|
||||||
const select = byId("aiGeneratorModel");
|
const select = byId("aiGeneratorModel");
|
||||||
select.options.length = 0;
|
select.options.length = 0;
|
||||||
GPT_MODELS.forEach(model => select.options.add(new Option(model, model)));
|
Object.keys(MODELS).forEach(model => select.options.add(new Option(model, model)));
|
||||||
select.value = localStorage.getItem("fmg-ai-model") || GPT_MODELS[0];
|
select.value = localStorage.getItem("fmg-ai-model");
|
||||||
|
if (!select.value || !MODELS[select.value]) select.value = DEFAULT_MODEL;
|
||||||
|
|
||||||
|
const provider = MODELS[select.value];
|
||||||
|
byId("aiGeneratorKey").value = localStorage.getItem(`fmg-ai-kl-${provider}`) || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generate(button) {
|
async function generate(button) {
|
||||||
const key = byId("aiGeneratorKey").value;
|
const key = byId("aiGeneratorKey").value;
|
||||||
if (!key) return tip("Please enter an OpenAI API key", true, "error", 4000);
|
if (!key) return tip("Please enter an API key", true, "error", 4000);
|
||||||
localStorage.setItem("fmg-ai-kl", key);
|
|
||||||
|
|
||||||
const model = byId("aiGeneratorModel").value;
|
const model = byId("aiGeneratorModel").value;
|
||||||
if (!model) return tip("Please select a model", true, "error", 4000);
|
if (!model) return tip("Please select a model", true, "error", 4000);
|
||||||
localStorage.setItem("fmg-ai-model", model);
|
localStorage.setItem("fmg-ai-model", model);
|
||||||
|
|
||||||
|
const provider = MODELS[model];
|
||||||
|
localStorage.setItem(`fmg-ai-kl-${provider}`, key);
|
||||||
|
|
||||||
const prompt = byId("aiGeneratorPrompt").value;
|
const prompt = byId("aiGeneratorPrompt").value;
|
||||||
if (!prompt) return tip("Please enter a prompt", true, "error", 4000);
|
if (!prompt) return tip("Please enter a prompt", true, "error", 4000);
|
||||||
|
|
||||||
const temperature = parseFloat(byId("aiGeneratorTemperature").value);
|
const temperature = byId("aiGeneratorTemperature").valueAsNumber;
|
||||||
if (isNaN(temperature) || temperature < 0 || temperature > 2) {
|
if (isNaN(temperature)) return tip("Temperature must be a number", true, "error", 4000);
|
||||||
return tip("Temperature must be a number between 0 and 2", true, "error", 4000);
|
localStorage.setItem("fmg-ai-temperature", temperature);
|
||||||
}
|
|
||||||
localStorage.setItem("fmg-ai-temperature", temperature.toString());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
button.disabled = true;
|
button.disabled = true;
|
||||||
const resultArea = byId("aiGeneratorResult");
|
const resultArea = byId("aiGeneratorResult");
|
||||||
resultArea.value = "";
|
|
||||||
resultArea.disabled = true;
|
resultArea.disabled = true;
|
||||||
|
resultArea.value = "";
|
||||||
|
const onContent = content => (resultArea.value += content);
|
||||||
|
|
||||||
const response = await fetch("https://api.openai.com/v1/chat/completions", {
|
await PROVIDERS[provider].generate({key, model, prompt, temperature, onContent});
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: `Bearer ${key}`
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
model,
|
|
||||||
messages: [
|
|
||||||
{role: "system", content: SYSTEM_MESSAGE},
|
|
||||||
{role: "user", content: prompt}
|
|
||||||
],
|
|
||||||
temperature: temperature,
|
|
||||||
stream: true // Enable streaming
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const json = await response.json();
|
|
||||||
throw new Error(json?.error?.message || "Failed to generate");
|
|
||||||
}
|
|
||||||
|
|
||||||
const reader = response.body.getReader();
|
|
||||||
const decoder = new TextDecoder("utf-8");
|
|
||||||
let buffer = "";
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
const {done, value} = await reader.read();
|
|
||||||
if (done) break;
|
|
||||||
|
|
||||||
buffer += decoder.decode(value, {stream: true});
|
|
||||||
const lines = buffer.split("\n");
|
|
||||||
|
|
||||||
for (let i = 0; i < lines.length - 1; i++) {
|
|
||||||
const line = lines[i].trim();
|
|
||||||
if (line.startsWith("data: ") && line !== "data: [DONE]") {
|
|
||||||
try {
|
|
||||||
const jsonData = JSON.parse(line.slice(6));
|
|
||||||
const content = jsonData.choices[0].delta.content;
|
|
||||||
if (content) resultArea.value += content;
|
|
||||||
} catch (jsonError) {
|
|
||||||
console.warn("Failed to parse JSON:", jsonError, "Line:", line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer = lines[lines.length - 1];
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return tip(error.message, true, "error", 4000);
|
return tip(error.message, true, "error", 4000);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -1255,7 +1255,7 @@ async function editStates() {
|
||||||
|
|
||||||
async function editCultures() {
|
async function editCultures() {
|
||||||
if (customization) return;
|
if (customization) return;
|
||||||
const Editor = await import("../dynamic/editors/cultures-editor.js?v=1.105.11");
|
const Editor = await import("../dynamic/editors/cultures-editor.js?v=1.105.23");
|
||||||
Editor.open();
|
Editor.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
* Example: 1.102.2 -> Major version 1, Minor version 102, Patch version 2
|
* Example: 1.102.2 -> Major version 1, Minor version 102, Patch version 2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const VERSION = "1.105.22";
|
const VERSION = "1.106.00";
|
||||||
if (parseMapVersion(VERSION) !== VERSION) alert("versioning.js: Invalid format or parsing function");
|
if (parseMapVersion(VERSION) !== VERSION) alert("versioning.js: Invalid format or parsing function");
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue