Preserve approved pixel tower prototype as development baseline

This commit is contained in:
Codex
2026-09-09 07:51:16 +09:00
commit 423fd6dd2e
915 changed files with 95193 additions and 0 deletions
+220
View File
@@ -0,0 +1,220 @@
class_name ConstructionJob
extends RefCounted
enum State {
PLANNED,
BUILDING,
COMPLETED,
CANCELLED,
BLOCKED,
}
const MAX_PROGRESS := 10_000
const NORMAL_WORK_RATE := 10_000
var job_id: StringName = &""
var definition_id: StringName = &""
var origin := Vector3i.ZERO
var rotation := 0
var layer := 0
var reserved_cells: Array[Vector3i] = []
var progress := 0
var state: State = State.PLANNED
var state_reason := ""
var assigned_builder_ids: Array[StringName] = []
var construction_cost: Dictionary = {}
var build_minutes := 60
var work_units_done := 0
var created_at := 0
var started_at := -1
var completed_at := -1
var cancelled_at := -1
var facility_instance_id: StringName = &""
func configure(
p_job_id: StringName,
p_definition_id: StringName,
p_origin: Vector3i,
p_rotation: int,
p_layer: int,
p_reserved_cells: Array[Vector3i],
p_construction_cost: Dictionary,
p_build_minutes: int,
p_created_at: int
) -> ConstructionJob:
job_id = p_job_id
definition_id = p_definition_id
origin = p_origin
rotation = _normalize_rotation(p_rotation)
layer = p_layer
reserved_cells.assign(p_reserved_cells)
construction_cost = _normalize_cost(p_construction_cost)
build_minutes = maxi(p_build_minutes, 1)
created_at = maxi(p_created_at, 0)
return self
func advance_one_minute(work_rate_basis_points: int = NORMAL_WORK_RATE, absolute_minute: int = -1) -> bool:
if state == State.COMPLETED or state == State.CANCELLED:
return false
if progress >= MAX_PROGRESS:
return true
if work_rate_basis_points <= 0:
mark_blocked("No effective construction work was supplied.")
return false
if started_at < 0:
started_at = absolute_minute
state = State.BUILDING
state_reason = ""
work_units_done += work_rate_basis_points
progress = mini(MAX_PROGRESS, work_units_done / build_minutes)
return progress >= MAX_PROGRESS
func mark_blocked(reason: String) -> void:
if state == State.COMPLETED or state == State.CANCELLED:
return
state = State.BLOCKED
state_reason = reason
func mark_completed(instance_id: StringName, absolute_minute: int = -1) -> void:
progress = MAX_PROGRESS
state = State.COMPLETED
state_reason = ""
facility_instance_id = instance_id
completed_at = absolute_minute
func mark_cancelled(absolute_minute: int = -1) -> void:
state = State.CANCELLED
state_reason = ""
cancelled_at = absolute_minute
func is_terminal() -> bool:
return state == State.COMPLETED or state == State.CANCELLED
func refundable_cost() -> Dictionary:
var refund: Dictionary = {}
var remaining_basis_points := maxi(MAX_PROGRESS - progress, 0)
for resource_name: Variant in construction_cost:
var amount := int(construction_cost[resource_name])
refund[StringName(resource_name)] = amount * remaining_basis_points / MAX_PROGRESS
return refund
func create_snapshot() -> Dictionary:
return {
&"job_id": String(job_id),
&"definition_id": String(definition_id),
&"origin": [origin.x, origin.y, origin.z],
&"rotation": rotation,
&"layer": layer,
&"reserved_cells": _serialize_cells(reserved_cells),
&"progress": progress,
&"state": State.keys()[state],
&"state_reason": state_reason,
&"assigned_builder_ids": _string_names_to_strings(assigned_builder_ids),
&"construction_cost": construction_cost.duplicate(true),
&"build_minutes": build_minutes,
&"work_units_done": work_units_done,
&"created_at": created_at,
&"started_at": started_at,
&"completed_at": completed_at,
&"cancelled_at": cancelled_at,
&"facility_instance_id": String(facility_instance_id),
}
static func from_snapshot(snapshot: Dictionary) -> ConstructionJob:
if not _is_valid_snapshot(snapshot):
return null
var job := ConstructionJob.new()
job.job_id = StringName(snapshot.get(&"job_id", ""))
job.definition_id = StringName(snapshot.get(&"definition_id", ""))
job.origin = _parse_cell(snapshot.get(&"origin", []))
job.rotation = _normalize_rotation(int(snapshot.get(&"rotation", 0)))
job.layer = int(snapshot.get(&"layer", job.origin.z))
job.reserved_cells = _parse_cells(snapshot.get(&"reserved_cells", []))
job.progress = clampi(int(snapshot.get(&"progress", 0)), 0, MAX_PROGRESS)
var state_index := State.keys().find(String(snapshot.get(&"state", "PLANNED")))
if state_index < 0:
return null
job.state = state_index as State
job.state_reason = String(snapshot.get(&"state_reason", ""))
var saved_builders: Variant = snapshot.get(&"assigned_builder_ids", [])
if saved_builders is Array:
for builder_id: Variant in saved_builders:
job.assigned_builder_ids.append(StringName(builder_id))
job.construction_cost = _normalize_cost(snapshot.get(&"construction_cost", {}))
job.build_minutes = maxi(int(snapshot.get(&"build_minutes", 60)), 1)
job.work_units_done = maxi(int(snapshot.get(&"work_units_done", 0)), 0)
job.created_at = maxi(int(snapshot.get(&"created_at", 0)), 0)
job.started_at = int(snapshot.get(&"started_at", -1))
job.completed_at = int(snapshot.get(&"completed_at", -1))
job.cancelled_at = int(snapshot.get(&"cancelled_at", -1))
job.facility_instance_id = StringName(snapshot.get(&"facility_instance_id", ""))
return job
static func _is_valid_snapshot(snapshot: Dictionary) -> bool:
if String(snapshot.get(&"job_id", "")).is_empty():
return false
if String(snapshot.get(&"definition_id", "")).is_empty():
return false
if not snapshot.get(&"origin", null) is Array:
return false
if not snapshot.get(&"reserved_cells", null) is Array:
return false
if not snapshot.get(&"construction_cost", null) is Dictionary:
return false
return true
static func _normalize_cost(source: Variant) -> Dictionary:
var normalized: Dictionary = {}
if not source is Dictionary:
return normalized
for resource_name: Variant in source:
normalized[StringName(resource_name)] = maxi(int(source[resource_name]), 0)
return normalized
static func _normalize_rotation(value: int) -> int:
var normalized := value % 360
if normalized < 0:
normalized += 360
return (normalized / 90) * 90
static func _parse_cell(source: Variant) -> Vector3i:
if not source is Array or source.size() != 3:
return Vector3i.ZERO
return Vector3i(int(source[0]), int(source[1]), int(source[2]))
static func _parse_cells(source: Variant) -> Array[Vector3i]:
var cells: Array[Vector3i] = []
if not source is Array:
return cells
for value: Variant in source:
if value is Array and value.size() == 3:
cells.append(_parse_cell(value))
return cells
static func _serialize_cells(source: Array[Vector3i]) -> Array[Array]:
var serialized: Array[Array] = []
for cell: Vector3i in source:
serialized.append([cell.x, cell.y, cell.z])
return serialized
static func _string_names_to_strings(source: Array[StringName]) -> Array[String]:
var serialized: Array[String] = []
for value: StringName in source:
serialized.append(String(value))
return serialized
@@ -0,0 +1 @@
uid://csul0q7j7m1a3
File diff suppressed because it is too large Load Diff
@@ -0,0 +1 @@
uid://cmjm3lvgmc06d
File diff suppressed because it is too large Load Diff
@@ -0,0 +1 @@
uid://b6sa4hwanps1l
+116
View File
@@ -0,0 +1,116 @@
class_name PlacementReport
extends RefCounted
const ERROR_INVALID_DEFINITION := &"INVALID_DEFINITION"
const ERROR_MISSING_DEPENDENCY := &"MISSING_DEPENDENCY"
const ERROR_OUT_OF_BOUNDS := &"OUT_OF_BOUNDS"
const ERROR_ZONE_MISMATCH := &"ZONE_MISMATCH"
const ERROR_LAYER_MISMATCH := &"LAYER_MISMATCH"
const ERROR_OVERLAP := &"OVERLAP"
const ERROR_NOT_EXCAVATED := &"NOT_EXCAVATED"
const ERROR_UNSUPPORTED := &"UNSUPPORTED"
const ERROR_INSUFFICIENT_RESOURCES := &"INSUFFICIENT_RESOURCES"
var can_build := false
var error_codes: Array[StringName] = []
var reasons: Array[Dictionary] = []
var cells: Array[Vector3i] = []
var out_of_bounds_cells: Array[Vector3i] = []
var zone_mismatch_cells: Array[Vector3i] = []
var layer_mismatch_cells: Array[Vector3i] = []
var occupied_cells: Array[Vector3i] = []
var unexcavated_cells: Array[Vector3i] = []
var unsupported_cells: Array[Vector3i] = []
var access_points: Array[Vector3i] = []
var mana_connection := false
var total_cost: Dictionary = {}
var missing_resources: Dictionary = {}
var build_time := 0
var predicted_environment_delta: Dictionary = {}
var predicted_operating_cost: Dictionary = {}
var predicted_heat := 0
func add_error(
code: StringName,
reason: String,
affected_cells: Array = [],
details: Dictionary = {}
) -> void:
if not error_codes.has(code):
error_codes.append(code)
var normalized_cells: Array[Vector3i] = []
for cell: Variant in affected_cells:
if cell is Vector3i:
normalized_cells.append(cell)
reasons.append({
&"code": code,
&"message": reason,
&"cells": normalized_cells,
&"details": details.duplicate(true),
})
can_build = false
func finalize() -> PlacementReport:
can_build = error_codes.is_empty()
return self
func has_error(code: StringName) -> bool:
return error_codes.has(code)
func reason_for(code: StringName) -> Dictionary:
for reason: Dictionary in reasons:
if StringName(reason.get(&"code", &"")) == code:
return reason.duplicate(true)
return {}
func to_dictionary() -> Dictionary:
var serialized_reasons: Array[Dictionary] = []
for reason: Dictionary in reasons:
var serialized := reason.duplicate(true)
serialized[&"code"] = String(reason.get(&"code", &""))
serialized[&"cells"] = _serialize_cells(reason.get(&"cells", []))
serialized_reasons.append(serialized)
return {
&"can_build": can_build,
&"error_codes": _string_names_to_strings(error_codes),
&"reasons": serialized_reasons,
&"cells": _serialize_cells(cells),
&"out_of_bounds_cells": _serialize_cells(out_of_bounds_cells),
&"zone_mismatch_cells": _serialize_cells(zone_mismatch_cells),
&"layer_mismatch_cells": _serialize_cells(layer_mismatch_cells),
&"occupied_cells": _serialize_cells(occupied_cells),
&"unexcavated_cells": _serialize_cells(unexcavated_cells),
&"unsupported_cells": _serialize_cells(unsupported_cells),
&"access_points": _serialize_cells(access_points),
&"mana_connection": mana_connection,
&"total_cost": total_cost.duplicate(true),
&"missing_resources": missing_resources.duplicate(true),
&"build_time": build_time,
&"predicted_environment_delta": predicted_environment_delta.duplicate(true),
&"predicted_operating_cost": predicted_operating_cost.duplicate(true),
&"predicted_heat": predicted_heat,
}
static func _serialize_cells(source: Variant) -> Array[Array]:
var serialized: Array[Array] = []
if not source is Array:
return serialized
for cell: Variant in source:
if cell is Vector3i:
serialized.append([cell.x, cell.y, cell.z])
return serialized
static func _string_names_to_strings(source: Array[StringName]) -> Array[String]:
var serialized: Array[String] = []
for value: StringName in source:
serialized.append(String(value))
return serialized
@@ -0,0 +1 @@
uid://bqgwlfqero41j