OpenLiberty/scripts/map_builder.gd

186 lines
5.8 KiB
GDScript3
Raw Permalink Normal View History

2022-11-15 16:56:41 +07:00
extends Node
2025-03-04 13:57:57 +07:00
var items: Dictionary[int, ItemDef]
2022-11-19 05:33:24 +07:00
var itemchilds: Array[TDFX]
2022-11-17 17:38:22 +07:00
var placements: Array[ItemPlacement]
2022-11-20 05:55:40 +07:00
var collisions: Array[ColFile]
2022-11-15 16:56:41 +07:00
var map: Node3D
var _loaded := false
2022-11-15 16:56:41 +07:00
func _ready() -> void:
2022-11-15 16:56:41 +07:00
var file := FileAccess.open(GameManager.gta_path + "data/gta3.dat", FileAccess.READ)
assert(file != null, "%d" % FileAccess.get_open_error())
while not file.eof_reached():
var line := file.get_line()
if not line.begins_with("#"):
var tokens := line.split(" ", false)
if tokens.size() > 0:
match tokens[0]:
"IDE":
_read_map_data(tokens[1], _read_ide_line)
2022-11-20 04:45:58 +07:00
"COLFILE":
2022-11-20 07:31:12 +07:00
var colfile := AssetLoader.open(GameManager.gta_path + tokens[2])
while colfile.get_position() < colfile.get_length():
collisions.append(ColFile.new(colfile))
2022-11-15 16:56:41 +07:00
"IPL":
_read_map_data(tokens[1], _read_ipl_line)
"CDIMAGE":
AssetLoader.load_cd_image(tokens[1])
2022-11-15 16:56:41 +07:00
_:
push_warning("implement %s" % tokens[0])
2022-11-19 05:33:24 +07:00
for child in itemchilds:
items[child.parent].childs.append(child)
2022-11-20 05:55:40 +07:00
for colfile in collisions:
if colfile.model_id in items:
items[colfile.model_id].colfile = colfile
else:
for k in items:
var item := items[k] as ItemDef
if item.model_name.matchn(colfile.model_name):
items[k].colfile = colfile
2022-11-20 04:45:58 +07:00
2022-11-15 16:56:41 +07:00
func _read_ide_line(section: String, tokens: Array[String]):
2022-11-19 05:33:24 +07:00
var item := ItemDef.new()
var id := tokens[0].to_int()
2022-11-15 16:56:41 +07:00
match section:
"objs":
2022-11-17 17:38:22 +07:00
item.model_name = tokens[1]
item.txd_name = tokens[2]
2022-11-17 17:49:00 +07:00
item.render_distance = tokens[4].to_float()
2022-11-17 17:38:22 +07:00
item.flags = tokens[tokens.size() - 1].to_int()
items[id] = item
2022-11-15 16:56:41 +07:00
"tobj":
# TODO: Timed objects
2022-11-17 17:38:22 +07:00
item.model_name = tokens[1]
item.txd_name = tokens[2]
items[id] = item
2022-11-19 05:33:24 +07:00
"2dfx":
2022-11-19 08:08:01 +07:00
var parent := tokens[0].to_int()
2025-03-04 14:25:47 +07:00
# Convert GTA to Godot coordinate system
2022-11-19 08:08:01 +07:00
var position := Vector3(
tokens[1].to_float(),
2025-03-02 14:37:28 +07:00
tokens[3].to_float(),
-tokens[2].to_float() )
2022-11-19 08:08:01 +07:00
var color := Color(
tokens[4].to_float() / 255,
tokens[5].to_float() / 255,
2024-08-15 19:25:32 -03:00
tokens[6].to_float() / 255 )
2022-11-19 05:33:24 +07:00
match tokens[8].to_int():
0:
var lightdef := TDFXLight.new()
2022-11-19 08:08:01 +07:00
lightdef.parent = parent
lightdef.position = position
lightdef.color = color
lightdef.render_distance = tokens[11].to_float()
lightdef.range = tokens[12].to_float()
lightdef.shadow_intensity = tokens[15].to_int()
2022-11-19 05:33:24 +07:00
itemchilds.append(lightdef)
var type:
push_warning("implement 2DFX type %d" % type)
2022-11-15 16:56:41 +07:00
func _read_ipl_line(section: String, tokens: Array[String]):
match section:
"inst":
2022-11-17 17:38:22 +07:00
var placement := ItemPlacement.new()
placement.id = tokens[0].to_int()
placement.model_name = tokens[1].to_lower()
2025-03-04 14:25:47 +07:00
# Convert GTA to Godot coordinate system
2022-11-17 17:38:22 +07:00
placement.position = Vector3(
2022-11-15 16:56:41 +07:00
tokens[2].to_float(),
2025-03-02 14:37:28 +07:00
tokens[4].to_float(),
-tokens[3].to_float(), )
2025-03-04 14:25:47 +07:00
# Scale conversion follows the same pattern
2022-11-17 17:38:22 +07:00
placement.scale = Vector3(
2022-11-15 16:56:41 +07:00
tokens[5].to_float(),
2025-03-02 14:37:28 +07:00
tokens[7].to_float(),
tokens[6].to_float(), )
2025-03-04 14:25:47 +07:00
# Quaternion conversion requires negating components
2022-11-17 17:38:22 +07:00
placement.rotation = Quaternion(
2022-11-18 03:52:32 +07:00
-tokens[8].to_float(),
-tokens[10].to_float(),
2025-03-02 14:37:28 +07:00
-tokens[9].to_float(),
2024-08-15 19:25:32 -03:00
tokens[11].to_float(), )
2022-11-17 17:38:22 +07:00
placements.append(placement)
2022-11-15 16:56:41 +07:00
func _read_map_data(path: String, line_handler: Callable) -> void:
2022-11-18 11:33:52 +07:00
var file := AssetLoader.open(path)
2024-08-15 19:25:32 -03:00
assert(file != null, "%d" % FileAccess.get_open_error() )
2022-11-15 16:56:41 +07:00
var section: String
while not file.eof_reached():
var line := file.get_line()
if line.length() == 0 or line.begins_with("#"):
continue
var tokens := line.replace(" ", "").split(",", false)
if tokens.size() == 1:
section = tokens[0]
else:
line_handler.call(section, tokens)
2022-11-15 17:59:27 +07:00
func clear_map() -> void:
2022-11-15 16:56:41 +07:00
map = Node3D.new()
2022-11-19 05:06:08 +07:00
func spawn_placement(ipl: ItemPlacement) -> Node3D:
return spawn(ipl.id, ipl.model_name, ipl.position, ipl.scale, ipl.rotation)
2022-11-17 17:38:22 +07:00
2022-11-19 05:06:08 +07:00
func spawn(id: int, model_name: String, position: Vector3, scale: Vector3, rotation: Quaternion) -> Node3D:
2022-11-17 17:38:22 +07:00
var item := items[id] as ItemDef
2022-11-17 19:31:09 +07:00
if item.flags & 0x40:
return Node3D.new()
var instance := StreamedMesh.new(item)
instance.position = position
instance.scale = scale
instance.quaternion = rotation
instance.visibility_range_end = item.render_distance
2022-11-19 05:33:24 +07:00
for child in item.childs:
if child is TDFXLight:
var light := OmniLight3D.new()
light.position = child.position
light.light_color = child.color
2022-11-19 08:08:01 +07:00
light.distance_fade_enabled = true
# TODO: Remove half distance when https://github.com/godotengine/godot/issues/56657 is solved
light.distance_fade_begin = child.render_distance / 2.0
2022-11-19 08:08:01 +07:00
light.omni_range = child.range
light.light_energy = float(child.shadow_intensity) / 20.0
# light.shadow_enabled = true
2022-11-19 08:08:01 +07:00
instance.add_child(light)
2022-11-20 05:55:40 +07:00
var sb := StaticBody3D.new()
if item.colfile != null:
for collision in item.colfile.collisions:
var colshape := CollisionShape3D.new()
if collision is ColFile.TBox:
var aabb := AABB()
2025-03-04 14:25:47 +07:00
# Get min and max positions from collision box
var min_pos := collision.min as Vector3
var max_pos := collision.max as Vector3
# Ensure AABB has positive size by sorting min/max for each axis
aabb.position = Vector3(
min(min_pos.x, max_pos.x),
min(min_pos.y, max_pos.y),
min(min_pos.z, max_pos.z)
)
aabb.end = Vector3(
max(min_pos.x, max_pos.x),
max(min_pos.y, max_pos.y),
max(min_pos.z, max_pos.z)
)
# Only create the shape if size is valid
if aabb.size.x > 0 and aabb.size.y > 0 and aabb.size.z > 0:
var shape := BoxShape3D.new()
shape.size = aabb.size
colshape.shape = shape
colshape.position = aabb.get_center()
sb.add_child(colshape)
else:
sb.add_child(colshape)
2022-11-20 06:40:40 +07:00
if item.colfile.vertices.size() > 0:
var colshape := CollisionShape3D.new()
var shape := ConcavePolygonShape3D.new()
shape.set_faces(item.colfile.vertices)
colshape.shape = shape
sb.add_child(colshape)
2022-11-20 05:55:40 +07:00
instance.add_child(sb)
2022-11-19 08:08:01 +07:00
return instance