Skip to content

Commit

Permalink
Fix Tearing Issues (#11)
Browse files Browse the repository at this point in the history
* Fix tearing using "overlayNum" strategy from Civ6EGRM, but need to also add edge cases from there?

* experiment with looking for next terrain

* Reduce size of compressed data start search string

* increase next terrain search length

* handle duplicate civs

* try adding stringr to cran list
  • Loading branch information
mrosack authored Jul 5, 2023
1 parent a13a00a commit df76aff
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 37 deletions.
85 changes: 56 additions & 29 deletions src/civ6_save_renderer/parse_map/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const zlib = require('zlib');
function decompress(savefile) {
const civsav = savefile;
const bufstartindex =
civsav.indexOf(Buffer.from([0, 0, 0, 0, 0, 1, 0, 0x78, 0x9c])) + 7;
civsav.indexOf(Buffer.from([0, 0, 1, 0, 0x78, 0x9c])) + 4;
const bufendindex = civsav.lastIndexOf(Buffer.from([0x00, 0x00, 0xFF, 0xFF]));

const data = civsav.slice(bufstartindex, bufendindex);
Expand Down Expand Up @@ -51,6 +51,11 @@ function savetomap(savefile) {
while (width === 0) {
mapWidthStartIndex += 1;
mapWidthStartIndex = bin.indexOf(mapWidthSearchBuffer, mapWidthStartIndex);

if (mapWidthStartIndex == -1) {
throw new Error(`Couldn't find map width start index...`)
}

width = bin.readInt16LE(mapWidthStartIndex + 8);

if (width < 0) {
Expand Down Expand Up @@ -90,37 +95,21 @@ function savetomap(savefile) {
'flags1': bin.readUInt8(mindex + 48), // bits: [is_pillaged, road_pillaged??, has_road, is_capital_or_citystate, -, river_sw, river_e, river_se]
'flags2': bin.readUInt8(mindex + 49), // bits: [cliff_sw, cliff_e, cliff_se, -, -, is_impassable, is_owned, -]
'flags3': bin.readUInt8(mindex + 50), // bits: [is_ice, -, -, -, -, -, -, -]
'flags4': bin.readUInt8(mindex + 51), // bits: [buffer length 24, buffer length 44, -, -, -, -, -, -]
'flags5': bin.readUInt8(mindex + 52), // empty?
'flags6': bin.readUInt8(mindex + 53), // empty?
'flags7': bin.readUInt8(mindex + 54), // empty?
'overlayNum': bin.readUint32LE(mindex + 51),
}
mindex += 55;

let buflength = 0;

if (obj['flags4'] & 1) {
// tile produces/captures co2?
obj['buffer1'] = bin.slice(mindex, mindex + 24).toString('hex');
obj['buffer1_flag'] = bin.readUInt8(mindex + 20);
mindex += 24;

if (obj['buffer1_flag'] & 1) {
// tile is ski resort or tunnel??
obj['buffer2'] = bin.slice(mindex, mindex + 20).toString('hex');
mindex += 20;
} else {
obj['buffer2'] = '';
}
} else if (obj['flags4'] & 2) {
obj['buffer1'] = bin.slice(mindex, mindex + 24).toString('hex');
obj['buffer1_flag'] = bin.readUInt8(mindex + 20);
obj['buffer2'] = bin.slice(mindex + 24, mindex + 44).toString('hex');
mindex += 44;

let buflength = {
1: 24,
2: 44,
3: 64
}[obj.overlayNum];

if (buflength) {
obj['buffer'] = bin.slice(mindex, mindex + buflength).toString('hex');
mindex += buflength;
} else {
obj['buffer1'] = '';
obj['buffer1_flag'] = '';
obj['buffer2'] = '';
obj['buffer'] = '';
}

if (obj['flags2'] & 64) {
Expand All @@ -138,6 +127,44 @@ function savetomap(savefile) {
obj['owner'] = '';
obj['world_wonder'] = '';
}

// Validate next tile terrain to get us synced back up if buffer is bad
if (i < tiles - 1) {
const terrains = [
2213004848,
1855786096,
1602466867,
4226188894,
3872285854,
2746853616,
3852995116,
3108058291,
1418772217,
1223859883,
3949113590,
3746160061,
1743422479,
3842183808,
699483892,
1248885265,
1204357597
];

let nextTerrainOffset = 0;

const SEARCH_LENGTH = 1000;

while (
nextTerrainOffset < SEARCH_LENGTH &&
!terrains.includes(bin.readUint32LE(mindex + nextTerrainOffset))
) {
nextTerrainOffset++;
}

if (nextTerrainOffset < SEARCH_LENGTH) {
mindex = mindex - 12 + nextTerrainOffset;
}
}

obj['tile_length'] = mindex - orig_mindex;

Expand Down
2 changes: 1 addition & 1 deletion src/civ6_save_renderer/plot_map/config.vsh.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ functionality:
platforms:
- type: docker
image: eddelbuettel/r2u:22.04
setup:
setup:
- type: r
cran:
- ggforce
Expand Down
27 changes: 20 additions & 7 deletions src/civ6_save_renderer/plot_map/helper.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ library(purrr, warn.conflicts = FALSE)
library(dplyr, warn.conflicts = FALSE)
library(ggplot2, warn.conflicts = FALSE)
library(tibble, warn.conflicts = FALSE)
library(stringr)

requireNamespace("ggforce", quietly = TRUE)
requireNamespace("civ6saves", quietly = TRUE)
Expand Down Expand Up @@ -50,21 +51,33 @@ make_map_plot <- function(game_data, map_data) {
# get leader info
owner_ids <- map_data$owner %>% unique() %>% sort()

civs = game_data$CIVS %>% transmute(owner = row_number() - 1L, leader = LEADER_NAME)

# assign colours to civs
leader_colours <- bind_rows(
game_data$CIVS %>%
transmute(owner = row_number() - 1L, leader = LEADER_NAME) %>%
civs %>%
left_join(civ6saves::leaders, by = "leader") %>%
rename(leader_inner_colour = leader_outer_colour, leader_outer_colour = leader_inner_colour) %>%
transmute(
owner,
leader,
leader_name = ifelse(is.na(leader_name), stringr::str_to_title(stringr::str_replace_all(stringr::str_replace(leader, "LEADER_", ""), "_", " ")), leader_name),
leader_outer_colour = ifelse(is.na(leader_outer_colour), default_colours[owner], leader_outer_colour),
leader_inner_colour = ifelse(is.na(leader_inner_colour), default_colours[length(default_colours) - 1 - owner], leader_inner_colour)
leader_name =
str_replace_all(
make.unique(
ifelse(
is.na(leader_name),
stringr::str_to_title(stringr::str_replace_all(stringr::str_replace(leader, "LEADER_", ""), "_", " ")),
leader_name
),
sep= " "
),
"(\\d+)$", function(x) as.numeric(x) + 1
),
leader_outer_colour = ifelse(is.na(leader_outer_colour) | length(which(civs$leader == leader) > 1), default_colours[owner], leader_outer_colour),
leader_inner_colour = ifelse(is.na(leader_inner_colour) | length(which(civs$leader == leader) > 1), default_colours[length(default_colours) - 1 - owner], leader_inner_colour)
),
tibble(
owner = setdiff(owner_ids, c(seq_len(nrow(game_data$CIVS)) - 1, 62L, 255L))
owner = setdiff(owner_ids, c(seq_len(nrow(civs)) - 1, 62L, 255L))
) %>% mutate(
leader = NA_character_,
leader_name = paste0("City State ", seq_along(owner)),
Expand Down Expand Up @@ -115,7 +128,7 @@ make_map_plot <- function(game_data, map_data) {

cities <- tab %>% group_by(owner, city_1) %>% filter(district == min(district)) %>% ungroup()

players <- game_data$ACTORS %>% filter(ACTOR_TYPE == "CIVILIZATION_LEVEL_FULL_CIV") %>% select(leader = LEADER_NAME) %>% left_join(leader_colours, by = "leader")
players <- civs %>% left_join(leader_colours, by = "owner")

g <- g0 +
ggforce::geom_regon(aes(r = civ6saves:::xy_ratio * .9), tab %>% filter(feature_name == "Ice"), fill = civ6saves::feature_palette[["Ice"]], alpha = .4) +
Expand Down

0 comments on commit df76aff

Please sign in to comment.