mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-20 13:50:46 +00:00
Add new assets and update room definitions: Introduce a comprehensive list of available object assets in available_objects.txt. Add multiple new object images and room JSON/TMJ files for room_ceo2, room_closet2, room_office2, and room_servers2. Update existing room files to enhance gameplay experience and ensure proper asset integration. Implement scripts for managing corrupted GID references and external tileset removal to maintain map integrity.
This commit is contained in:
131
scripts/check_corrupted_gids.py
Executable file
131
scripts/check_corrupted_gids.py
Executable file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import json
|
||||
import os
|
||||
|
||||
"""
|
||||
Script to identify corrupted GID references in Tiled map
|
||||
This will help find objects that reference non-existent tileset entries
|
||||
"""
|
||||
|
||||
MAP_FILE = "assets/rooms/room_reception2.json"
|
||||
|
||||
def get_valid_gid_ranges(map_data):
|
||||
"""Get all valid GID ranges from tilesets"""
|
||||
valid_ranges = []
|
||||
|
||||
for tileset in map_data.get('tilesets', []):
|
||||
firstgid = tileset.get('firstgid', 0)
|
||||
tilecount = tileset.get('tilecount', 0)
|
||||
|
||||
if tilecount:
|
||||
max_gid = firstgid + tilecount
|
||||
valid_ranges.append((firstgid, max_gid, tileset.get('name', 'unknown')))
|
||||
else:
|
||||
# Handle tilesets with undefined tilecount
|
||||
valid_ranges.append((firstgid, firstgid + 1, tileset.get('name', 'unknown')))
|
||||
|
||||
return valid_ranges
|
||||
|
||||
def is_gid_valid(gid, valid_ranges):
|
||||
"""Check if a GID is valid (exists in any tileset)"""
|
||||
for start, end, name in valid_ranges:
|
||||
if start <= gid < end:
|
||||
return True, name
|
||||
return False, None
|
||||
|
||||
def check_layer_objects(layer_name, objects, valid_ranges):
|
||||
"""Check objects in a layer for invalid GIDs"""
|
||||
corrupted_objects = []
|
||||
|
||||
for obj in objects:
|
||||
gid = obj.get('gid', 0)
|
||||
if gid > 0: # Only check objects with GIDs
|
||||
is_valid, tileset_name = is_gid_valid(gid, valid_ranges)
|
||||
if not is_valid:
|
||||
corrupted_objects.append({
|
||||
'id': obj.get('id', 'unknown'),
|
||||
'gid': gid,
|
||||
'x': obj.get('x', 0),
|
||||
'y': obj.get('y', 0),
|
||||
'name': obj.get('name', ''),
|
||||
'layer': layer_name
|
||||
})
|
||||
|
||||
return corrupted_objects
|
||||
|
||||
def main():
|
||||
"""Main function to check for corrupted GIDs"""
|
||||
print("🔍 Checking for Corrupted GID References")
|
||||
print("=" * 50)
|
||||
|
||||
if not os.path.exists(MAP_FILE):
|
||||
print(f"❌ Map file not found: {MAP_FILE}")
|
||||
return
|
||||
|
||||
try:
|
||||
with open(MAP_FILE, 'r') as f:
|
||||
map_data = json.load(f)
|
||||
except Exception as e:
|
||||
print(f"❌ Error reading map file: {e}")
|
||||
return
|
||||
|
||||
# Get valid GID ranges
|
||||
valid_ranges = get_valid_gid_ranges(map_data)
|
||||
print(f"📊 Found {len(valid_ranges)} tilesets with valid GID ranges:")
|
||||
for start, end, name in valid_ranges:
|
||||
print(f" {name}: GIDs {start}-{end-1}")
|
||||
|
||||
print()
|
||||
|
||||
# Check each layer
|
||||
all_corrupted = []
|
||||
|
||||
for layer in map_data.get('layers', []):
|
||||
layer_name = layer.get('name', 'unknown')
|
||||
objects = layer.get('objects', [])
|
||||
|
||||
if objects:
|
||||
corrupted = check_layer_objects(layer_name, objects, valid_ranges)
|
||||
if corrupted:
|
||||
all_corrupted.extend(corrupted)
|
||||
print(f"❌ Layer '{layer_name}': {len(corrupted)} corrupted objects")
|
||||
for obj in corrupted[:5]: # Show first 5
|
||||
print(f" - Object ID {obj['id']}: GID {obj['gid']} at ({obj['x']}, {obj['y']})")
|
||||
if len(corrupted) > 5:
|
||||
print(f" ... and {len(corrupted) - 5} more")
|
||||
else:
|
||||
print(f"✅ Layer '{layer_name}': All objects valid")
|
||||
|
||||
print()
|
||||
|
||||
if all_corrupted:
|
||||
print(f"🚨 Found {len(all_corrupted)} corrupted objects total")
|
||||
print()
|
||||
print("📋 Summary by GID:")
|
||||
|
||||
# Group by GID
|
||||
gid_counts = {}
|
||||
for obj in all_corrupted:
|
||||
gid = obj['gid']
|
||||
if gid not in gid_counts:
|
||||
gid_counts[gid] = []
|
||||
gid_counts[gid].append(obj)
|
||||
|
||||
for gid in sorted(gid_counts.keys()):
|
||||
count = len(gid_counts[gid])
|
||||
print(f" GID {gid}: {count} objects")
|
||||
|
||||
print()
|
||||
print("🔧 Recommended Actions:")
|
||||
print("1. Open the map in Tiled Editor")
|
||||
print("2. Look for pink/magenta placeholder tiles")
|
||||
print("3. Replace corrupted objects with valid ones from the tileset")
|
||||
print("4. Save the map")
|
||||
|
||||
else:
|
||||
print("✅ No corrupted GID references found!")
|
||||
print("The map should work correctly in Phaser.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
165
scripts/fix_corrupted_gids.py
Executable file
165
scripts/fix_corrupted_gids.py
Executable file
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
|
||||
"""
|
||||
Script to remove objects with corrupted GID references from Tiled map
|
||||
This will clean up the JSON file by removing objects that reference non-existent tileset entries
|
||||
"""
|
||||
|
||||
MAP_FILE = "assets/rooms/room_reception2.json"
|
||||
BACKUP_FILE = f"assets/rooms/room_reception2.json.backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
||||
|
||||
def get_valid_gid_ranges(map_data):
|
||||
"""Get all valid GID ranges from tilesets"""
|
||||
valid_ranges = []
|
||||
|
||||
for tileset in map_data.get('tilesets', []):
|
||||
firstgid = tileset.get('firstgid', 0)
|
||||
tilecount = tileset.get('tilecount', 0)
|
||||
|
||||
if tilecount:
|
||||
max_gid = firstgid + tilecount
|
||||
valid_ranges.append((firstgid, max_gid, tileset.get('name', 'unknown')))
|
||||
else:
|
||||
# Handle tilesets with undefined tilecount
|
||||
valid_ranges.append((firstgid, firstgid + 1, tileset.get('name', 'unknown')))
|
||||
|
||||
return valid_ranges
|
||||
|
||||
def is_gid_valid(gid, valid_ranges):
|
||||
"""Check if a GID is valid (exists in any tileset)"""
|
||||
for start, end, name in valid_ranges:
|
||||
if start <= gid < end:
|
||||
return True, name
|
||||
return False, None
|
||||
|
||||
def clean_layer_objects(layer_name, objects, valid_ranges):
|
||||
"""Remove objects with invalid GIDs from a layer"""
|
||||
original_count = len(objects)
|
||||
valid_objects = []
|
||||
removed_objects = []
|
||||
|
||||
for obj in objects:
|
||||
gid = obj.get('gid', 0)
|
||||
if gid > 0: # Only check objects with GIDs
|
||||
is_valid, tileset_name = is_gid_valid(gid, valid_ranges)
|
||||
if is_valid:
|
||||
valid_objects.append(obj)
|
||||
else:
|
||||
removed_objects.append({
|
||||
'id': obj.get('id', 'unknown'),
|
||||
'gid': gid,
|
||||
'x': obj.get('x', 0),
|
||||
'y': obj.get('y', 0),
|
||||
'name': obj.get('name', ''),
|
||||
'layer': layer_name
|
||||
})
|
||||
else:
|
||||
# Keep objects without GIDs (like collision shapes, etc.)
|
||||
valid_objects.append(obj)
|
||||
|
||||
removed_count = original_count - len(valid_objects)
|
||||
return valid_objects, removed_objects, removed_count
|
||||
|
||||
def main():
|
||||
"""Main function to clean corrupted GIDs"""
|
||||
print("🧹 Cleaning Corrupted GID References")
|
||||
print("=" * 50)
|
||||
|
||||
if not os.path.exists(MAP_FILE):
|
||||
print(f"❌ Map file not found: {MAP_FILE}")
|
||||
return
|
||||
|
||||
# Create backup
|
||||
print(f"📁 Creating backup: {BACKUP_FILE}")
|
||||
shutil.copy2(MAP_FILE, BACKUP_FILE)
|
||||
|
||||
try:
|
||||
with open(MAP_FILE, 'r') as f:
|
||||
map_data = json.load(f)
|
||||
except Exception as e:
|
||||
print(f"❌ Error reading map file: {e}")
|
||||
return
|
||||
|
||||
# Get valid GID ranges
|
||||
valid_ranges = get_valid_gid_ranges(map_data)
|
||||
print(f"📊 Valid GID ranges:")
|
||||
for start, end, name in valid_ranges:
|
||||
print(f" {name}: GIDs {start}-{end-1}")
|
||||
|
||||
print()
|
||||
|
||||
# Clean each layer
|
||||
total_removed = 0
|
||||
all_removed_objects = []
|
||||
|
||||
for layer in map_data.get('layers', []):
|
||||
layer_name = layer.get('name', 'unknown')
|
||||
objects = layer.get('objects', [])
|
||||
|
||||
if objects:
|
||||
valid_objects, removed_objects, removed_count = clean_layer_objects(layer_name, objects, valid_ranges)
|
||||
|
||||
if removed_count > 0:
|
||||
# Update the layer with cleaned objects
|
||||
layer['objects'] = valid_objects
|
||||
total_removed += removed_count
|
||||
all_removed_objects.extend(removed_objects)
|
||||
|
||||
print(f"🧹 Layer '{layer_name}': Removed {removed_count} corrupted objects")
|
||||
for obj in removed_objects:
|
||||
print(f" - Object ID {obj['id']}: GID {obj['gid']} at ({obj['x']}, {obj['y']})")
|
||||
else:
|
||||
print(f"✅ Layer '{layer_name}': No corrupted objects found")
|
||||
|
||||
print()
|
||||
|
||||
if total_removed > 0:
|
||||
# Write cleaned map file
|
||||
try:
|
||||
with open(MAP_FILE, 'w') as f:
|
||||
json.dump(map_data, f, indent=2)
|
||||
|
||||
print(f"✅ Successfully removed {total_removed} corrupted objects")
|
||||
print(f"💾 Updated map file: {MAP_FILE}")
|
||||
print(f"📁 Backup created: {BACKUP_FILE}")
|
||||
|
||||
print()
|
||||
print("📋 Summary of removed objects:")
|
||||
gid_counts = {}
|
||||
for obj in all_removed_objects:
|
||||
gid = obj['gid']
|
||||
if gid not in gid_counts:
|
||||
gid_counts[gid] = 0
|
||||
gid_counts[gid] += 1
|
||||
|
||||
for gid in sorted(gid_counts.keys()):
|
||||
count = gid_counts[gid]
|
||||
print(f" GID {gid}: {count} objects removed")
|
||||
|
||||
print()
|
||||
print("🎯 Next steps:")
|
||||
print("1. Open the map in Tiled Editor to verify the cleanup")
|
||||
print("2. Add any missing objects back using valid tileset entries")
|
||||
print("3. Save the map")
|
||||
print("4. Test the game to ensure it loads without errors")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error writing cleaned map file: {e}")
|
||||
print(f"🔄 Restoring from backup...")
|
||||
shutil.copy2(BACKUP_FILE, MAP_FILE)
|
||||
return
|
||||
|
||||
else:
|
||||
print("✅ No corrupted objects found!")
|
||||
print("The map is already clean.")
|
||||
# Remove backup since no changes were made
|
||||
os.remove(BACKUP_FILE)
|
||||
print(f"🗑️ Removed unnecessary backup: {BACKUP_FILE}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
108
scripts/remove_external_tilesets.py
Executable file
108
scripts/remove_external_tilesets.py
Executable file
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
|
||||
"""
|
||||
Script to remove external tileset references from Tiled map
|
||||
This will remove tilesets that reference external .tsx files, keeping only embedded tilesets
|
||||
"""
|
||||
|
||||
MAP_FILE = "assets/rooms/room_reception2.json"
|
||||
BACKUP_FILE = f"assets/rooms/room_reception2.json.backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
||||
|
||||
def main():
|
||||
"""Main function to remove external tileset references"""
|
||||
print("🧹 Removing External Tileset References")
|
||||
print("=" * 50)
|
||||
|
||||
if not os.path.exists(MAP_FILE):
|
||||
print(f"❌ Map file not found: {MAP_FILE}")
|
||||
return
|
||||
|
||||
# Create backup
|
||||
print(f"📁 Creating backup: {BACKUP_FILE}")
|
||||
shutil.copy2(MAP_FILE, BACKUP_FILE)
|
||||
|
||||
try:
|
||||
with open(MAP_FILE, 'r') as f:
|
||||
map_data = json.load(f)
|
||||
except Exception as e:
|
||||
print(f"❌ Error reading map file: {e}")
|
||||
return
|
||||
|
||||
# Check for external tilesets
|
||||
tilesets = map_data.get('tilesets', [])
|
||||
external_tilesets = []
|
||||
embedded_tilesets = []
|
||||
|
||||
for i, tileset in enumerate(tilesets):
|
||||
if 'source' in tileset:
|
||||
external_tilesets.append((i, tileset))
|
||||
print(f"❌ External tileset found: {tileset.get('source', 'unknown')} (firstgid: {tileset.get('firstgid', 'unknown')})")
|
||||
else:
|
||||
embedded_tilesets.append((i, tileset))
|
||||
print(f"✅ Embedded tileset: {tileset.get('name', 'unknown')} (firstgid: {tileset.get('firstgid', 'unknown')})")
|
||||
|
||||
print()
|
||||
|
||||
if not external_tilesets:
|
||||
print("✅ No external tileset references found!")
|
||||
print("The map is already clean.")
|
||||
# Remove backup since no changes were made
|
||||
os.remove(BACKUP_FILE)
|
||||
print(f"🗑️ Removed unnecessary backup: {BACKUP_FILE}")
|
||||
return
|
||||
|
||||
print(f"🚨 Found {len(external_tilesets)} external tileset references")
|
||||
print(f"✅ Found {len(embedded_tilesets)} embedded tilesets")
|
||||
|
||||
# Remove external tilesets (in reverse order to maintain indices)
|
||||
removed_count = 0
|
||||
for i, tileset in reversed(external_tilesets):
|
||||
tileset_name = tileset.get('name', 'unknown')
|
||||
tileset_source = tileset.get('source', 'unknown')
|
||||
firstgid = tileset.get('firstgid', 'unknown')
|
||||
|
||||
print(f"🗑️ Removing external tileset: {tileset_name} (source: {tileset_source}, firstgid: {firstgid})")
|
||||
tilesets.pop(i)
|
||||
removed_count += 1
|
||||
|
||||
# Update the map data
|
||||
map_data['tilesets'] = tilesets
|
||||
|
||||
print()
|
||||
print(f"✅ Successfully removed {removed_count} external tileset references")
|
||||
|
||||
# Write cleaned map file
|
||||
try:
|
||||
with open(MAP_FILE, 'w') as f:
|
||||
json.dump(map_data, f, indent=2)
|
||||
|
||||
print(f"💾 Updated map file: {MAP_FILE}")
|
||||
print(f"📁 Backup created: {BACKUP_FILE}")
|
||||
|
||||
print()
|
||||
print("📊 Remaining tilesets:")
|
||||
for tileset in tilesets:
|
||||
name = tileset.get('name', 'unknown')
|
||||
firstgid = tileset.get('firstgid', 'unknown')
|
||||
tilecount = tileset.get('tilecount', 'unknown')
|
||||
print(f" {name}: firstgid={firstgid}, tilecount={tilecount}")
|
||||
|
||||
print()
|
||||
print("🎯 Next steps:")
|
||||
print("1. Test the game - it should now load without external tileset errors")
|
||||
print("2. If you need the removed tileset, re-embed it in Tiled Editor")
|
||||
print("3. Save the map after making any changes")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error writing cleaned map file: {e}")
|
||||
print(f"🔄 Restoring from backup...")
|
||||
shutil.copy2(BACKUP_FILE, MAP_FILE)
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
216
scripts/update_tileset.js
Executable file
216
scripts/update_tileset.js
Executable file
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Script to update Tiled map with all objects from assets directory
|
||||
* This ensures all objects are included in the tileset with proper GIDs
|
||||
*/
|
||||
|
||||
const ASSETS_DIR = path.join(__dirname, '../assets/objects');
|
||||
const MAP_FILE = path.join(__dirname, '../assets/rooms/room_reception2.json');
|
||||
|
||||
// Object types to include
|
||||
const OBJECT_TYPES = [
|
||||
'bag', 'bin', 'briefcase', 'laptop', 'phone', 'pc', 'note', 'notes',
|
||||
'safe', 'suitcase', 'office-misc', 'plant', 'chair', 'picture', 'table'
|
||||
];
|
||||
|
||||
function getAllObjectFiles() {
|
||||
const files = [];
|
||||
|
||||
try {
|
||||
const entries = fs.readdirSync(ASSETS_DIR, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
if (entry.isFile() && entry.name.endsWith('.png')) {
|
||||
const baseName = entry.name.replace('.png', '');
|
||||
const category = getObjectCategory(baseName);
|
||||
|
||||
files.push({
|
||||
filename: entry.name,
|
||||
basename: baseName,
|
||||
category: category,
|
||||
path: `../objects/${entry.name}`
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error reading assets directory:', error);
|
||||
return [];
|
||||
}
|
||||
|
||||
return files.sort((a, b) => a.basename.localeCompare(b.basename));
|
||||
}
|
||||
|
||||
function getObjectCategory(filename) {
|
||||
const baseName = filename.replace('.png', '');
|
||||
|
||||
for (const type of OBJECT_TYPES) {
|
||||
if (baseName.includes(type)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return 'misc';
|
||||
}
|
||||
|
||||
function findHighestGID(mapData) {
|
||||
let highestGID = 0;
|
||||
|
||||
// Find the highest GID in the most recent objects tileset
|
||||
const objectsTilesets = mapData.tilesets.filter(ts =>
|
||||
ts.name === 'objects' || ts.name.includes('objects/')
|
||||
);
|
||||
|
||||
if (objectsTilesets.length > 0) {
|
||||
const latestTileset = objectsTilesets[objectsTilesets.length - 1];
|
||||
highestGID = latestTileset.firstgid + (latestTileset.tilecount || 0);
|
||||
}
|
||||
|
||||
return highestGID;
|
||||
}
|
||||
|
||||
function createTilesetEntry(file, gid) {
|
||||
return {
|
||||
id: gid - 1, // Tiled uses 0-based indexing
|
||||
image: file.path,
|
||||
imageheight: 16, // Default size, will be updated by Tiled
|
||||
imagewidth: 16
|
||||
};
|
||||
}
|
||||
|
||||
function updateMapFile(objectFiles) {
|
||||
try {
|
||||
const mapData = JSON.parse(fs.readFileSync(MAP_FILE, 'utf8'));
|
||||
|
||||
// Find the latest objects tileset
|
||||
const objectsTilesets = mapData.tilesets.filter(ts =>
|
||||
ts.name === 'objects' || ts.name.includes('objects/')
|
||||
);
|
||||
|
||||
if (objectsTilesets.length === 0) {
|
||||
console.error('No objects tileset found in map file');
|
||||
return;
|
||||
}
|
||||
|
||||
const latestTileset = objectsTilesets[objectsTilesets.length - 1];
|
||||
const startGID = latestTileset.firstgid + (latestTileset.tilecount || 0);
|
||||
|
||||
console.log(`Found latest objects tileset with firstgid: ${latestTileset.firstgid}`);
|
||||
console.log(`Current tilecount: ${latestTileset.tilecount || 0}`);
|
||||
console.log(`Next available GID: ${startGID}`);
|
||||
|
||||
// Check which objects are missing
|
||||
const existingImages = new Set();
|
||||
if (latestTileset.tiles) {
|
||||
latestTileset.tiles.forEach(tile => {
|
||||
if (tile.image) {
|
||||
const filename = path.basename(tile.image);
|
||||
existingImages.add(filename);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const missingObjects = objectFiles.filter(file =>
|
||||
!existingImages.has(file.filename)
|
||||
);
|
||||
|
||||
console.log(`Found ${objectFiles.length} total objects`);
|
||||
console.log(`Found ${existingImages.size} existing objects in tileset`);
|
||||
console.log(`Missing ${missingObjects.length} objects`);
|
||||
|
||||
if (missingObjects.length === 0) {
|
||||
console.log('All objects are already in the tileset!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Add missing objects to tileset
|
||||
const newTiles = [];
|
||||
let currentGID = startGID;
|
||||
|
||||
for (const file of missingObjects) {
|
||||
const tileEntry = createTilesetEntry(file, currentGID);
|
||||
newTiles.push(tileEntry);
|
||||
currentGID++;
|
||||
}
|
||||
|
||||
// Update tileset
|
||||
if (!latestTileset.tiles) {
|
||||
latestTileset.tiles = [];
|
||||
}
|
||||
|
||||
latestTileset.tiles.push(...newTiles);
|
||||
latestTileset.tilecount = (latestTileset.tilecount || 0) + newTiles.length;
|
||||
|
||||
console.log(`Added ${newTiles.length} new objects to tileset`);
|
||||
console.log(`New tilecount: ${latestTileset.tilecount}`);
|
||||
|
||||
// Write updated map file
|
||||
fs.writeFileSync(MAP_FILE, JSON.stringify(mapData, null, 2));
|
||||
console.log(`Updated map file: ${MAP_FILE}`);
|
||||
|
||||
// Generate Tiled command to open the map
|
||||
console.log('\nNext steps:');
|
||||
console.log('1. Open the map in Tiled Editor');
|
||||
console.log('2. The new objects should be available in the tileset');
|
||||
console.log('3. Place objects in your layers as needed');
|
||||
console.log('4. Save the map');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error updating map file:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
console.log('🔧 Tileset Update Script');
|
||||
console.log('========================');
|
||||
|
||||
// Check if assets directory exists
|
||||
if (!fs.existsSync(ASSETS_DIR)) {
|
||||
console.error(`Assets directory not found: ${ASSETS_DIR}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check if map file exists
|
||||
if (!fs.existsSync(MAP_FILE)) {
|
||||
console.error(`Map file not found: ${MAP_FILE}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Scanning assets directory: ${ASSETS_DIR}`);
|
||||
const objectFiles = getAllObjectFiles();
|
||||
|
||||
if (objectFiles.length === 0) {
|
||||
console.log('No object files found in assets directory');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Found ${objectFiles.length} object files`);
|
||||
|
||||
// Group by category
|
||||
const byCategory = {};
|
||||
objectFiles.forEach(file => {
|
||||
if (!byCategory[file.category]) {
|
||||
byCategory[file.category] = [];
|
||||
}
|
||||
byCategory[file.category].push(file);
|
||||
});
|
||||
|
||||
console.log('\nObjects by category:');
|
||||
Object.entries(byCategory).forEach(([category, files]) => {
|
||||
console.log(` ${category}: ${files.length} files`);
|
||||
});
|
||||
|
||||
console.log('\nUpdating map file...');
|
||||
updateMapFile(objectFiles);
|
||||
|
||||
console.log('\n✅ Script completed!');
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
|
||||
module.exports = { getAllObjectFiles, updateMapFile };
|
||||
184
scripts/update_tileset.py
Executable file
184
scripts/update_tileset.py
Executable file
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import json
|
||||
import glob
|
||||
from pathlib import Path
|
||||
|
||||
"""
|
||||
Script to update Tiled map with all objects from assets directory
|
||||
This ensures all objects are included in the tileset with proper GIDs
|
||||
"""
|
||||
|
||||
ASSETS_DIR = "assets/objects"
|
||||
MAP_FILE = "assets/rooms/room_reception2.json"
|
||||
|
||||
# Object types to include
|
||||
OBJECT_TYPES = [
|
||||
'bag', 'bin', 'briefcase', 'laptop', 'phone', 'pc', 'note', 'notes',
|
||||
'safe', 'suitcase', 'office-misc', 'plant', 'chair', 'picture', 'table'
|
||||
]
|
||||
|
||||
def get_all_object_files():
|
||||
"""Get all object files from the assets directory"""
|
||||
files = []
|
||||
|
||||
if not os.path.exists(ASSETS_DIR):
|
||||
print(f"❌ Assets directory not found: {ASSETS_DIR}")
|
||||
return files
|
||||
|
||||
for file_path in glob.glob(os.path.join(ASSETS_DIR, "*.png")):
|
||||
filename = os.path.basename(file_path)
|
||||
basename = filename.replace('.png', '')
|
||||
category = get_object_category(basename)
|
||||
|
||||
files.append({
|
||||
'filename': filename,
|
||||
'basename': basename,
|
||||
'category': category,
|
||||
'path': f"../objects/{filename}"
|
||||
})
|
||||
|
||||
return sorted(files, key=lambda x: x['basename'])
|
||||
|
||||
def get_object_category(filename):
|
||||
"""Determine the category of an object based on its filename"""
|
||||
for obj_type in OBJECT_TYPES:
|
||||
if obj_type in filename:
|
||||
return obj_type
|
||||
return 'misc'
|
||||
|
||||
def find_latest_objects_tileset(map_data):
|
||||
"""Find the latest objects tileset in the map data"""
|
||||
objects_tilesets = []
|
||||
|
||||
for tileset in map_data.get('tilesets', []):
|
||||
if tileset.get('name') == 'objects' or 'objects/' in tileset.get('name', ''):
|
||||
objects_tilesets.append(tileset)
|
||||
|
||||
if not objects_tilesets:
|
||||
return None
|
||||
|
||||
# Return the last one (most recent)
|
||||
return objects_tilesets[-1]
|
||||
|
||||
def create_tileset_entry(file_info, gid):
|
||||
"""Create a tileset entry for a file"""
|
||||
return {
|
||||
"id": gid - 1, # Tiled uses 0-based indexing
|
||||
"image": file_info['path'],
|
||||
"imageheight": 16, # Default size, will be updated by Tiled
|
||||
"imagewidth": 16
|
||||
}
|
||||
|
||||
def update_map_file(object_files):
|
||||
"""Update the map file with missing objects"""
|
||||
try:
|
||||
with open(MAP_FILE, 'r') as f:
|
||||
map_data = json.load(f)
|
||||
|
||||
# Find the latest objects tileset
|
||||
latest_tileset = find_latest_objects_tileset(map_data)
|
||||
|
||||
if not latest_tileset:
|
||||
print("❌ No objects tileset found in map file")
|
||||
return False
|
||||
|
||||
print(f"📋 Found latest objects tileset with firstgid: {latest_tileset.get('firstgid', 0)}")
|
||||
print(f"📊 Current tilecount: {latest_tileset.get('tilecount', 0)}")
|
||||
|
||||
# Check which objects are missing
|
||||
existing_images = set()
|
||||
if 'tiles' in latest_tileset:
|
||||
for tile in latest_tileset['tiles']:
|
||||
if 'image' in tile:
|
||||
filename = os.path.basename(tile['image'])
|
||||
existing_images.add(filename)
|
||||
|
||||
missing_objects = [f for f in object_files if f['filename'] not in existing_images]
|
||||
|
||||
print(f"📁 Found {len(object_files)} total objects")
|
||||
print(f"✅ Found {len(existing_images)} existing objects in tileset")
|
||||
print(f"❌ Missing {len(missing_objects)} objects")
|
||||
|
||||
if not missing_objects:
|
||||
print("🎉 All objects are already in the tileset!")
|
||||
return True
|
||||
|
||||
# Add missing objects to tileset
|
||||
start_gid = latest_tileset.get('firstgid', 0) + latest_tileset.get('tilecount', 0)
|
||||
new_tiles = []
|
||||
|
||||
for i, file_info in enumerate(missing_objects):
|
||||
gid = start_gid + i
|
||||
tile_entry = create_tileset_entry(file_info, gid)
|
||||
new_tiles.append(tile_entry)
|
||||
|
||||
# Update tileset
|
||||
if 'tiles' not in latest_tileset:
|
||||
latest_tileset['tiles'] = []
|
||||
|
||||
latest_tileset['tiles'].extend(new_tiles)
|
||||
latest_tileset['tilecount'] = latest_tileset.get('tilecount', 0) + len(new_tiles)
|
||||
|
||||
print(f"➕ Added {len(new_tiles)} new objects to tileset")
|
||||
print(f"📊 New tilecount: {latest_tileset['tilecount']}")
|
||||
|
||||
# Write updated map file
|
||||
with open(MAP_FILE, 'w') as f:
|
||||
json.dump(map_data, f, indent=2)
|
||||
|
||||
print(f"💾 Updated map file: {MAP_FILE}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error updating map file: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""Main function"""
|
||||
print("🔧 Tileset Update Script")
|
||||
print("========================")
|
||||
|
||||
# Check if map file exists
|
||||
if not os.path.exists(MAP_FILE):
|
||||
print(f"❌ Map file not found: {MAP_FILE}")
|
||||
return
|
||||
|
||||
print(f"📂 Scanning assets directory: {ASSETS_DIR}")
|
||||
object_files = get_all_object_files()
|
||||
|
||||
if not object_files:
|
||||
print("❌ No object files found in assets directory")
|
||||
return
|
||||
|
||||
print(f"📁 Found {len(object_files)} object files")
|
||||
|
||||
# Group by category
|
||||
by_category = {}
|
||||
for file_info in object_files:
|
||||
category = file_info['category']
|
||||
if category not in by_category:
|
||||
by_category[category] = []
|
||||
by_category[category].append(file_info)
|
||||
|
||||
print("\n📊 Objects by category:")
|
||||
for category, files in by_category.items():
|
||||
print(f" {category}: {len(files)} files")
|
||||
|
||||
print("\n🔄 Updating map file...")
|
||||
success = update_map_file(object_files)
|
||||
|
||||
if success:
|
||||
print("\n✅ Script completed successfully!")
|
||||
print("\n📝 Next steps:")
|
||||
print("1. Open the map in Tiled Editor")
|
||||
print("2. Check that all objects are available in the tileset")
|
||||
print("3. Place any missing objects in your layers")
|
||||
print("4. Save the map")
|
||||
print("\n🎯 This script ensures all objects from assets/objects/ are included in the tileset!")
|
||||
else:
|
||||
print("\n❌ Script failed. Please check the errors above.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user