new doc SAVE_FORMAT, new unihan font WenQuanYi

Former-commit-id: 654fe713ae8165ed37fc85535e9536b01a5fe611
Former-commit-id: 34468f4d34b3dfd4be01c48c7fab34fe04678a6b
This commit is contained in:
Song Minjae
2016-03-12 01:38:56 +09:00
parent 95092ea56c
commit 46a553d258
31 changed files with 298 additions and 97 deletions

View File

@@ -104,8 +104,9 @@
== (De)serialisation ==
* Custom binary + GSON
see SAVE_FORMAT
* Custom binary: Game map
* GSON: Actors, game configurations
== Actor being universal ==
* Utility tiles that have states (e.g. noteblock) are implemented using Actor.

View File

@@ -0,0 +1,55 @@
* Save meta
- Binary (for more security)
- Filename : world (with no extension)
Type Mnemonic Description
Byte[4] TESV Magic
Byte[n] name Savegame name, UTF-8
Byte null String terminator
Byte[8] terraseed Terrain seed
Byte[8] <arb name> possible other seeds
Byte[32] hash1 SHA-256 hash of worldinfo1 being stored
Byte[32] hash2 SHA-256 hash of worldinfo2 being stored
Byte[32] hash3 SHA-256 hash of worldinfo3 being stored
Byte[32] hash4 SHA-256 hash of worldinfo4 beihg stored (TEMD data) [32, 214, 42, 3, 76, ...]
* Actor data
- GZip'd GSON
- Filename : <refid> (with no extension)
* Prop data
- GZip'd CSV
- Filename : worldinfo1 -- tileprop.csv
worldinfo2 -- itemprop.csv (with no extension)
* Roguelike randomiser data
- GZip'd GSON
- Filename : worldinfo3
* Human-readable
- Tiles_list.txt -- list of tiles in csv
- Items_list.txt -- list of items in csv
== How it works ==
* If hash discrepancy is detected, (hash of csv in save dir != stored hash || hash of TEMD != stored hash)
printout "Save file corrupted. Continue?" with prompt "Yes/No"
Directory:
+--- <save1>
--- 2a93bc5fd...f823 Actor data
--- 423bdc838...93bd Actor data
--- Items_list.txt Human-readable
--- Tiles_list.txt Human-readable
--- world save meta
--- worldinfo1 tileprop
--- worldinfo2 itemprop
--- worldinfo3 Roguelike randomiser
--- worldinfo4 TEMD binary

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 673 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 673 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 KiB

View File

@@ -8,7 +8,7 @@ import org.newdawn.slick.Color;
public class Col216 implements LimitedColours {
private byte data;
private static int[] LOOKUP = {0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF};
private static transient final int[] LOOKUP = {0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF};
public static final int MUL = 6;
public static final int MUL_2 = MUL * MUL;

View File

@@ -8,7 +8,7 @@ import org.newdawn.slick.Color;
public class Col40 implements LimitedColours {
private char data;
private static int[] LOOKUP = {0,7,13,20,26,33,39,46,52,59,65,72,78,85,92,98,105,111,118,124
private static transient final int[] LOOKUP = {0,7,13,20,26,33,39,46,52,59,65,72,78,85,92,98,105,111,118,124
,131,137,144,150,157,163,170,177,183,190,196,203,209,216,222,229,235,242,248,255};
public static final int MUL = 40;

View File

@@ -19,11 +19,13 @@ public class GameFontBase implements Font {
static SpriteSheet extASheetEF;
static SpriteSheet kanaSheet;
static SpriteSheet cjkPunct;
static SpriteSheet uniHan;
// static SpriteSheet uniHan;
static SpriteSheet cyrilic;
static SpriteSheet cyrilicEF;
static SpriteSheet fullwidthForms;
static SpriteSheet uniPunct;
static SpriteSheet wenQuanYi_1;
static SpriteSheet wenQuanYi_2;
static final int JUNG_COUNT = 21;
static final int JONG_COUNT = 28;
@@ -50,6 +52,8 @@ public class GameFontBase implements Font {
static final int SHEET_CYRILIC_EF = 10;
static final int SHEET_FW_UNI = 11;
static final int SHEET_UNI_PUNCT = 12;
static final int SHEET_WENQUANYI_1 = 13;
static final int SHEET_WENQUANYI_2 = 14;
static SpriteSheet[] sheetKey;
static final Character[] asciiEFList = {
@@ -188,6 +192,14 @@ public class GameFontBase implements Font {
return (c >= 0x2000 && c < 0x2070);
}
private boolean isWenQuanYi1(char c) {
return (c >= 0x33F3 && c <= 0x69FC);
}
private boolean isWenQuanYi2(char c) {
return (c >= 0x69FD && c <= 0x9FDC);
}
/** */
private int asciiEFindexX(char c) {
@@ -270,6 +282,19 @@ public class GameFontBase implements Font {
return (c - 0x2000) / 16;
}
private int wenQuanYiIndexX(char c) {
// v Ext1 v Unihan
return (c - (c <= 0x4DB5 ? 0x33F3 : 0x33F3 + 0x4A)) % 32;
}
private int wenQuanYi1IndexY(char c) {
return (c - (c <= 0x4DB5 ? 0x33F3 : 0x33F3 + 0x4A)) / 32;
}
private int wenQuanYi2IndexY(char c) {
return (c - 0x69FD) / 32;
}
@Override
public int getWidth(String s) {
return getWidthSubstr(s, s.length());
@@ -304,7 +329,7 @@ public class GameFontBase implements Font {
len += W_LATIN_NARROW;
else if (c == SHEET_KANA || c == SHEET_HANGUL || c == SHEET_CJK_PUNCT)
len += W_CJK;
else if (c == SHEET_UNIHAN || c == SHEET_FW_UNI)
else if (c == SHEET_UNIHAN || c == SHEET_FW_UNI || c == SHEET_WENQUANYI_1 || c == SHEET_WENQUANYI_2)
len += W_UNIHAN;
else
len += W_LATIN_WIDE;
@@ -400,7 +425,7 @@ public class GameFontBase implements Font {
hangulSheet.endUse();
// unihan fonts
uniHan.startUse();
/*uniHan.startUse();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
@@ -417,7 +442,47 @@ public class GameFontBase implements Font {
}
}
uniHan.endUse();
uniHan.endUse();*/
// WenQuanYi 1
wenQuanYi_1.startUse();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (isWenQuanYi1(ch)) {
int glyphW = getWidth("" + ch);
wenQuanYi_1.renderInUse(
Math.round(x
+ getWidthSubstr(s, i + 1) - glyphW
)
, Math.round((H - H_UNIHAN) / 2 + y)
, wenQuanYiIndexX(ch)
, wenQuanYi1IndexY(ch)
);
}
}
wenQuanYi_1.endUse();
wenQuanYi_2.startUse();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (isWenQuanYi2(ch)) {
int glyphW = getWidth("" + ch);
wenQuanYi_2.renderInUse(
Math.round(x
+ getWidthSubstr(s, i + 1) - glyphW
)
, Math.round((H - H_UNIHAN) / 2 + y)
, wenQuanYiIndexX(ch)
, wenQuanYi2IndexY(ch)
);
}
}
wenQuanYi_2.endUse();
//ascii fonts
int prevInstance = -1;

View File

@@ -43,13 +43,13 @@ public class GameFontWhite extends GameFontBase {
"./res/graphics/fonts/cjkpunct.png"
, W_CJK, H_KANA
);
uniHan = new SpriteSheet(
/*uniHan = new SpriteSheet(
"./res/graphics/fonts/unifont_unihan"
+ ((!Terrarum.gameLocale.contains("zh"))
? "_ja" : "")
+".png"
, W_UNIHAN, H_UNIHAN
);
);*/
cyrilic = new SpriteSheet(
"./res/graphics/fonts/cyrilic_majuscule.png"
, W_LATIN_WIDE, H
@@ -66,6 +66,14 @@ public class GameFontWhite extends GameFontBase {
"./res/graphics/fonts/unipunct.png"
, W_LATIN_WIDE, H
);
wenQuanYi_1 = new SpriteSheet(
"./res/graphics/fonts/wenquanyi_11pt_part1.png"
, 16, 18, 2
);
wenQuanYi_2 = new SpriteSheet(
"./res/graphics/fonts/wenquanyi_11pt_part2.png"
, 16, 18, 2
);
SpriteSheet[] shk = {
asciiSheet
@@ -76,23 +84,26 @@ public class GameFontWhite extends GameFontBase {
, extASheetEF
, kanaSheet
, cjkPunct
, uniHan
//, uniHan
, null
, cyrilic
, cyrilicEF
, fullwidthForms
, uniPunct
, wenQuanYi_1
, wenQuanYi_2
};
sheetKey = shk;
}
@Override
public void reloadUnihan() throws SlickException {
uniHan = new SpriteSheet(
/*uniHan = new SpriteSheet(
"./res/graphics/fonts/unifont_unihan"
+ ((!Terrarum.gameLocale.contains("zh"))
? "_ja" : "")
+".png"
, W_UNIHAN, H_UNIHAN
);
);*/
}
}

View File

@@ -2,20 +2,18 @@ package com.Torvald.Terrarum.Actors;
import com.Torvald.Terrarum.GameItem.InventoryItem;
import com.Torvald.Terrarum.GameItem.ItemCodex;
import com.sun.istack.internal.Nullable;
import com.Torvald.Terrarum.Nullable;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
/**
* Created by minjaesong on 16-01-15.
*/
public class ActorInventory {
@Nullable private int capacityByCount;
@Nullable private int capacityByWeight;
private @Nullable int capacityByCount;
private @Nullable int capacityByWeight;
private int capacityMode;
/**
@@ -23,13 +21,13 @@ public class ActorInventory {
*/
private HashMap<Long, Integer> itemList;
public final transient int CAPACITY_MODE_COUNT = 1;
public final transient int CAPACITY_MODE_WEIGHT = 2;
public transient final int CAPACITY_MODE_COUNT = 1;
public transient final int CAPACITY_MODE_WEIGHT = 2;
/**
* Construct new inventory with specified capacity.
* @param capacity if is_weight is true, killogramme value is required, counts of items otherwise.
* @param is_weight
* @param is_weight whether encumbrance should be calculated upon the weight of the inventory. False to use item counts.
*/
public ActorInventory(int capacity, boolean is_weight) {
if (is_weight) {
@@ -79,7 +77,6 @@ public class ActorInventory {
float weight = 0;
for (Map.Entry<Long, Integer> item : itemList.entrySet()) {
//weight += item.getWeight();
weight += ItemCodex.getItem(item.getKey()).getWeight()
* item.getValue();
}
@@ -87,23 +84,36 @@ public class ActorInventory {
return weight;
}
public float getTotalCount() {
public int getTotalCount() {
int count = 0;
for (Map.Entry<Long, Integer> item : itemList.entrySet()) {
//weight += item.getWeight();
count += item.getValue();
}
return count;
}
public int getTotalUniqueCount() {
return itemList.entrySet().size();
}
public void appendToPocket(InventoryItem item) {
appendToPocket(item, 1);
}
public void appendToPocket(InventoryItem item, int count) {
long key = item.getItemID();
// if (key == Player.PLAYER_REF_ID)
// throw new IllegalArgumentException("Attempted to put player into the inventory.");
if (itemList.containsKey(key))
itemList.put(key, itemList.get(key) + 1);
// increment amount if it already has specified item
itemList.put(key, itemList.get(key) + count);
else
itemList.put(key, 1);
// add new entry if it does not have specified item
itemList.put(key, count);
}
/**
@@ -114,8 +124,11 @@ public class ActorInventory {
if (getCapacityMode() == CAPACITY_MODE_WEIGHT) {
return (capacityByWeight < getTotalWeight());
}
else {
else if (getCapacityMode() == CAPACITY_MODE_COUNT) {
return (capacityByCount < getTotalWeight());
}
else {
throw new UnsupportedOperationException("capacity mode not valid.");
}
}
}

View File

@@ -35,12 +35,12 @@ public class ActorWithBody implements Actor, Visible, Glowing {
* +3.0 is acceleration. You __accumulate__ acceleration to the velocity.
*/
private volatile @NotNull float veloX, veloY;
private final transient float VELO_HARD_LIMIT = 10000;
private transient final float VELO_HARD_LIMIT = 10000;
boolean grounded = false;
@Nullable transient SpriteAnimation sprite;
@Nullable transient SpriteAnimation spriteGlow;
transient @Nullable SpriteAnimation sprite;
transient @Nullable SpriteAnimation spriteGlow;
/** Default to 'false' */
private boolean visible = false;
/** Default to 'true' */
@@ -55,20 +55,21 @@ public class ActorWithBody implements Actor, Visible, Glowing {
/**
* Positions: top-left point
*/
private volatile @NotNull Hitbox hitbox, nextHitbox;
private volatile @NotNull Hitbox hitbox;
private volatile transient @NotNull Hitbox nextHitbox;
/**
* Physical properties
*/
@NonZero private volatile transient float scale = 1;
@NonZero private volatile transient float mass = 2f;
private final transient float MASS_LOWEST = 2f;
private volatile transient @NonZero float scale = 1;
private volatile transient @NonZero float mass = 2f;
private transient final float MASS_LOWEST = 2f;
/** Valid range: [0, 1] */
private float elasticity = 0;
private final transient float ELASTICITY_MAX = 0.993f;
@NoNegative private float density = 1000;
private transient final float ELASTICITY_MAX = 0.993f;
private @NoNegative float density = 1000;
private static final transient int TSIZE = MapDrawer.TILE_SIZE;
private static transient final int TSIZE = MapDrawer.TILE_SIZE;
private static int AUTO_CLIMB_RATE = TSIZE / 8;
/**
@@ -77,55 +78,55 @@ public class ActorWithBody implements Actor, Visible, Glowing {
* s^2 = 1/FPS = 1/60 if FPS is targeted to 60
* meter to pixel : 24/FPS
*/
private final transient float METER = 24f;
private transient final float METER = 24f;
/**
* [m / s^2] * SI_TO_GAME_ACC -> [px / IFrame^2]
*/
private final transient float SI_TO_GAME_ACC = METER / FastMath.sqr(Terrarum.TARGET_FPS);
private transient final float SI_TO_GAME_ACC = METER / FastMath.sqr(Terrarum.TARGET_FPS);
/**
* [m / s] * SI_TO_GAME_VEL -> [px / IFrame]
*/
private final transient float SI_TO_GAME_VEL = METER / Terrarum.TARGET_FPS;
private transient final float SI_TO_GAME_VEL = METER / Terrarum.TARGET_FPS;
private float gravitation;
private final transient float DRAG_COEFF = 1f;
private transient float gravitation;
private transient final float DRAG_COEFF = 1f;
private final transient int CONTACT_AREA_TOP = 0;
private final transient int CONTACT_AREA_RIGHT = 1;
private final transient int CONTACT_AREA_BOTTOM = 2;
private final transient int CONTACT_AREA_LEFT = 3;
private transient final int CONTACT_AREA_TOP = 0;
private transient final int CONTACT_AREA_RIGHT = 1;
private transient final int CONTACT_AREA_BOTTOM = 2;
private transient final int CONTACT_AREA_LEFT = 3;
private final transient int UD_COMPENSATOR_MAX = TSIZE;
private final transient int LR_COMPENSATOR_MAX = TSIZE;
private final transient int TILE_AUTOCLIMB_RATE = 4;
private transient final int UD_COMPENSATOR_MAX = TSIZE;
private transient final int LR_COMPENSATOR_MAX = TSIZE;
private transient final int TILE_AUTOCLIMB_RATE = 4;
/**
* A constant to make falling faster so that the game is more playable
*/
private final transient float G_MUL_PLAYABLE_CONST = 1.4142f;
private transient final float G_MUL_PLAYABLE_CONST = 1.4142f;
long referenceID;
private final transient int EVENT_MOVE_TOP = 0;
private final transient int EVENT_MOVE_RIGHT = 1;
private final transient int EVENT_MOVE_BOTTOM = 2;
private final transient int EVENT_MOVE_LEFT = 3;
private final transient int EVENT_MOVE_NONE = -1;
private transient final int EVENT_MOVE_TOP = 0;
private transient final int EVENT_MOVE_RIGHT = 1;
private transient final int EVENT_MOVE_BOTTOM = 2;
private transient final int EVENT_MOVE_LEFT = 3;
private transient final int EVENT_MOVE_NONE = -1;
int eventMoving = EVENT_MOVE_NONE; // cannot collide both X-axis and Y-axis, or else jump control breaks up.
transient int eventMoving = EVENT_MOVE_NONE; // cannot collide both X-axis and Y-axis, or else jump control breaks up.
/**
* in milliseconds
*/
public final transient int INVINCIBILITY_TIME = 500;
public transient final int INVINCIBILITY_TIME = 500;
/**
* Will ignore fluid resistance if (submerged height / actor height) <= this var
*/
private final transient float FLUID_RESISTANCE_IGNORE_THRESHOLD_RATIO = 0.2f;
private final transient float FLUID_RESISTANCE_APPLY_FULL_RATIO = 0.5f;
private transient final float FLUID_RESISTANCE_IGNORE_THRESHOLD_RATIO = 0.2f;
private transient final float FLUID_RESISTANCE_APPLY_FULL_RATIO = 0.5f;
private GameMap map;
private transient GameMap map;
/**
* Give new random ReferenceID and initialise ActorValue
@@ -352,8 +353,8 @@ public class ActorWithBody implements Actor, Visible, Glowing {
else {
}
}
else if (veloX <= 0.5) {
System.out.println("collidingleft");
else if (veloX <= -0.5) {
// System.out.println("collidingleft");
// order of the if-elseif chain is IMPORTANT
if (isColliding(CONTACT_AREA_LEFT) && !isColliding(CONTACT_AREA_RIGHT)) {
adjustHitLeft();
@@ -367,9 +368,9 @@ public class ActorWithBody implements Actor, Visible, Glowing {
}
}
else {
System.out.println("updatehorizontal - |velo| < 0.5");
// System.out.println("updatehorizontal - |velo| < 0.5");
if (isColliding(CONTACT_AREA_LEFT) || isColliding(CONTACT_AREA_RIGHT)) {
// elasticReflectX();
elasticReflectX();
}
}
}

View File

@@ -21,17 +21,17 @@ import java.util.HashSet;
*/
public class Player extends ActorWithBody implements Controllable, Pocketed, Factionable, Luminous {
@Nullable public Controllable vehicleRiding;
public transient @Nullable Controllable vehicleRiding;
int jumpCounter = 0;
int walkPowerCounter = 0;
private final transient int MAX_JUMP_LENGTH = 17; // use 17; in internal frames
private transient final int MAX_JUMP_LENGTH = 17; // use 17; in internal frames
/**
* experimental value.
*/
// private final transient float JUMP_ACCELERATION_MOD = ???f / 10000f; //quadratic mode
private final transient float JUMP_ACCELERATION_MOD = 170f / 10000f; //linear mode
private final transient int WALK_FRAMES_TO_MAX_ACCEL = 6;
// private transient final float JUMP_ACCELERATION_MOD = ???f / 10000f; //quadratic mode
private transient final float JUMP_ACCELERATION_MOD = 170f / 10000f; //linear mode
private transient final int WALK_FRAMES_TO_MAX_ACCEL = 6;
public float readonly_totalX = 0, readonly_totalY = 0;
@@ -39,29 +39,29 @@ public class Player extends ActorWithBody implements Controllable, Pocketed, Fac
@NotNull int walkHeading;
private final transient int LEFT = 1;
private final transient int RIGHT = 2;
private transient final int LEFT = 1;
private transient final int RIGHT = 2;
private final transient int KEY_NULL = -1;
private int prevHMoveKey = KEY_NULL;
private int prevVMoveKey = KEY_NULL;
private transient final int KEY_NULL = -1;
private transient int prevHMoveKey = KEY_NULL;
private transient int prevVMoveKey = KEY_NULL;
static final transient float ACCEL_MULT_IN_FLIGHT = 0.48f;
static final transient float WALK_STOP_ACCEL = 0.32f;
static final transient float WALK_ACCEL_BASE = 0.32f;
static transient final float ACCEL_MULT_IN_FLIGHT = 0.48f;
static transient final float WALK_STOP_ACCEL = 0.32f;
static transient final float WALK_ACCEL_BASE = 0.32f;
private boolean noClip = false;
public static final long PLAYER_REF_ID = 0x51621D;
public static transient final long PLAYER_REF_ID = 0x51621D;
private final transient float AXIS_POSMAX = 1.0f;
private final transient int GAMEPAD_JUMP = 5;
private transient final float AXIS_POSMAX = 1.0f;
private transient final int GAMEPAD_JUMP = 5;
private final transient int TSIZE = MapDrawer.TILE_SIZE;
private transient final int TSIZE = MapDrawer.TILE_SIZE;
private HashSet<Faction> factionSet = new HashSet<>();
private final transient int BASE_DENSITY = 1020;
private transient final int BASE_DENSITY = 1020;
/**

View File

@@ -104,8 +104,9 @@
== (De)serialisation ==
* Custom binary + GSON
see SAVE_FORMAT
* Custom binary: Game map
* GSON: Actors, game configurations
== Actor being universal ==
* Utility tiles that have states (e.g. noteblock) are implemented using Actor.

View File

@@ -3,30 +3,30 @@ package com.Torvald.Terrarum;
import com.Torvald.ColourUtil.Col4096;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.HashMap;
/**
* Created by minjaesong on 16-02-23.
*/
public class RoguelikeRandomiser {
private static final int[] POTION_PRIMARY_COLSET = {15, 15, 8, 8, 0, 0};
private static transient final int[] POTION_PRIMARY_COLSET = {15, 15, 8, 8, 0, 0};
private static Hashtable<Integer, Col4096> potionColours;
private static Hashtable<Col4096, Boolean> coloursDiscovered;
private static HashMap<Integer, Col4096> potionColours;
private static HashMap<Col4096, Boolean> coloursDiscovered;
private static ArrayList<Col4096> coloursTaken;
private static final int POTION_HEAL_TIER1 = 0x00;
private static final int POTION_HEAL_TIRE2 = 0x01;
private static transient final int POTION_HEAL_TIER1 = 0x00;
private static transient final int POTION_HEAL_TIRE2 = 0x01;
private static final int POTION_MAGIC_REGEN_TIER1 = 0x10;
private static transient final int POTION_MAGIC_REGEN_TIER1 = 0x10;
private static final int POTION_BERSERK_TIER1 = 0x20;
private static transient final int POTION_BERSERK_TIER1 = 0x20;
public RoguelikeRandomiser() {
potionColours = new Hashtable<>();
potionColours = new HashMap<>();
coloursTaken = new ArrayList<>();
}

View File

@@ -0,0 +1,55 @@
* Save meta
- Binary (for more security)
- Filename : world (with no extension)
Type Mnemonic Description
Byte[4] TESV Magic
Byte[n] name Savegame name, UTF-8
Byte null String terminator
Byte[8] terraseed Terrain seed
Byte[8] <arb name> possible other seeds
Byte[32] hash1 SHA-256 hash of worldinfo1 being stored
Byte[32] hash2 SHA-256 hash of worldinfo2 being stored
Byte[32] hash3 SHA-256 hash of worldinfo3 being stored
Byte[32] hash4 SHA-256 hash of worldinfo4 beihg stored (TEMD data) [32, 214, 42, 3, 76, ...]
* Actor data
- GZip'd GSON
- Filename : <refid> (with no extension)
* Prop data
- GZip'd CSV
- Filename : worldinfo1 -- tileprop.csv
worldinfo2 -- itemprop.csv (with no extension)
* Roguelike randomiser data
- GZip'd GSON
- Filename : worldinfo3
* Human-readable
- Tiles_list.txt -- list of tiles in csv
- Items_list.txt -- list of items in csv
== How it works ==
* If hash discrepancy is detected, (hash of csv in save dir != stored hash || hash of TEMD != stored hash)
printout "Save file corrupted. Continue?" with prompt "Yes/No"
Directory:
+--- <save1>
--- 2a93bc5fd...f823 Actor data
--- 423bdc838...93bd Actor data
--- Items_list.txt Human-readable
--- Tiles_list.txt Human-readable
--- world save meta
--- worldinfo1 tileprop
--- worldinfo2 itemprop
--- worldinfo3 Roguelike randomiser
--- worldinfo4 TEMD binary

View File

@@ -25,8 +25,7 @@ public class TilePropCodex {
try {
// todo verify CSV using pre-calculated SHA256 hash
List<CSVRecord> records = CSVFetcher.readCSV("" +
"./src/com/Torvald/Terrarum/TileProperties/propdata" +
".csv");
"./src/com/Torvald/Terrarum/TileProperties/tileprop.csv");
System.out.println("[TilePropCodex] Building tile properties table");

View File

Can't render this file because it contains an unexpected character in line 1 and column 18.