diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fea8d3f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.config/ +.vscode/ +src/bin +src/**/obj \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..d3d7c4b --- /dev/null +++ b/build.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +echo "Building..." +exec dotnet build diff --git a/plan.md b/plan.md new file mode 100644 index 0000000..5edd300 --- /dev/null +++ b/plan.md @@ -0,0 +1,167 @@ +### Network Engineering Simulator - Pseudocode Specification +```plaintext +// GLOBAL STATE +world: 3D voxel space (solid/air) +devices: List = [] +connections: List = [] +credits: int = 0 +technicians: List = [free_starter_bot] + +// DEVICE TYPES +struct Framework: + id: IP_address (A.B.C.D where 0≤A,B,C,D≤3) + packet_gen_rate: float // packets/sec + +struct Router: + ports: [Device|null, Device|null] + +struct Hub: + ports: [Device|null, Device|null, Device|null] + rotation: enum{ CLOCKWISE, COUNTERCLOCKWISE } + active_port: int (0,1,2) + +// ECONOMY +shop_items = { + "cable": {cost:1, qty:20}, + "router": {cost:2, qty:1}, + "hub": {cost:10, qty:1}, + "technician": {cost:10000, qty:1}, + "drill_fuel": {cost:20, qty:100} +} + +// CONSTRUCTION SYSTEM +function toggle_networking_mode(enabled): + if enabled: + use_technician_bots() + else: + free_instant_build() + +function place_device(type, position): + if networking_mode: + assign_to_technician(type, position) + else: + spawn_device(type, position) + +function drill_volume(start, end): + blocks = calculate_blocks(start, end) + if networking_mode: + consume_fuel(blocks) + technician.drill(start, end) + else: + instant_clear_volume(start, end) + +function create_connection(devA, devB): + distance = distance(devA.pos, devB.pos) + cable_cost = ceil(distance / 3.0) + if credits < cable_cost: return FAIL + + // Ray collision check (ignore shared planes) + if has_collision(devA.pos, devB.pos): return FAIL + + credits -= cable_cost + connection = new Connection(devA, devB, cable_cost) + connections.add(connection) + +// HUB MANAGEMENT +function connect_to_hub(device, hub, port_index): + hub.ports[port_index] = device + create_connection(device, hub) + +function rotate_hubs(): // Called every second + for hub in all_hubs: + if hub.rotation == CLOCKWISE: + hub.active_port = (hub.active_port + 1) % 3 + else: + hub.active_port = (hub.active_port - 1) % 3 + +// PACKET SYSTEM +function generate_packets(): + for framework in all_frameworks: + dest = random_valid_ip() + spawn_packet(framework, dest) + +function route_packets(): // Called every second + for packet in all_packets: + current = packet.current_device + next = get_next_hop(current, packet.dest) + packet.hops += connection_cost(current, next) + packet.move_to(next) + +// ECONOMY & UI +function free_money_button(): + if credits < 10: + credits += 100 + +function calculate_earnings(): + for packet in delivered_packets: + credits += BASE_REWARD * packet.hops + +// MAIN GAME LOOP +every_frame: + handle_player_input() + render_world() + +every_second: + generate_packets() + route_packets() + calculate_earnings() + rotate_hubs() +``` + +### Key Constants +```plaintext +BASE_REWARD = 1.0 // Credit per hop +IP_RANGE = [0,1,2,3] // Valid IP digits +``` + +### Simplified Device Behavior +```plaintext +Router: + Input → Output (direct passthrough) + +Hub: + Always routes to active_port + Port rotation occurs AFTER packet transfer + +Connection: + Cost = ceil(distance/3) + Each connection adds 'cost' hops to packets +``` + +### Input Handling Pseudocode +```plaintext +on_mouse_click: + if in_build_mode: + place_device(selected_type, world_position) + + if in_drill_mode: + drill_volume(selection_start, selection_end) + + if in_connect_mode: + create_connection(selected_device1, selected_device2) + + if ui_element_clicked("free_money"): + free_money_button() +``` + +### Collision Detection +```plaintext +function has_collision(posA, posB): + // Ignore collisions on shared planes + if same_x_plane(posA, posB): ignore YZ + if same_y_plane(posA, posB): ignore XZ + if same_z_plane(posA, posB): ignore XY + + return raycast(posA, posB) hits non-device solid +``` + +This specification contains all mechanics in condensed pseudocode format, covering: +- IP-based routing (0-3 digits) +- Cable cost/distance formula +- 1-second packet synchronization +- Networking mode toggle +- Collision-aware connections +- Hop-based economy +- Free money condition +- Device placement logic +- Hub rotation system diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..ef64ddd --- /dev/null +++ b/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +echo "Running..." +exec dotnet run --no-build --project src/ diff --git a/src/Content/Content.mgcb b/src/Content/Content.mgcb new file mode 100644 index 0000000..ddc4c36 --- /dev/null +++ b/src/Content/Content.mgcb @@ -0,0 +1,15 @@ + +#----------------------------- Global Properties ----------------------------# + +/outputDir:bin/$(Platform) +/intermediateDir:obj/$(Platform) +/platform:DesktopGL +/config: +/profile:Reach +/compress:False + +#-------------------------------- References --------------------------------# + + +#---------------------------------- Content ---------------------------------# + diff --git a/src/Game1.cs b/src/Game1.cs new file mode 100644 index 0000000..061b2b7 --- /dev/null +++ b/src/Game1.cs @@ -0,0 +1,51 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; + +namespace tunnet; + +public class Game1 : Game +{ + private GraphicsDeviceManager _graphics; + private SpriteBatch _spriteBatch; + + public Game1() + { + _graphics = new GraphicsDeviceManager(this); + Content.RootDirectory = "Content"; + IsMouseVisible = true; + } + + protected override void Initialize() + { + // TODO: Add your initialization logic here + + base.Initialize(); + } + + protected override void LoadContent() + { + _spriteBatch = new SpriteBatch(GraphicsDevice); + + // TODO: use this.Content to load your game content here + } + + protected override void Update(GameTime gameTime) + { + if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) + Exit(); + + // TODO: Add your update logic here + + base.Update(gameTime); + } + + protected override void Draw(GameTime gameTime) + { + GraphicsDevice.Clear(Color.CornflowerBlue); + + // TODO: Add your drawing code here + + base.Draw(gameTime); + } +} diff --git a/src/Icon.bmp b/src/Icon.bmp new file mode 100644 index 0000000..2b48165 Binary files /dev/null and b/src/Icon.bmp differ diff --git a/src/Icon.ico b/src/Icon.ico new file mode 100644 index 0000000..7d9dec1 Binary files /dev/null and b/src/Icon.ico differ diff --git a/src/Program.cs b/src/Program.cs new file mode 100644 index 0000000..36a8345 --- /dev/null +++ b/src/Program.cs @@ -0,0 +1,2 @@ +using var game = new tunnet.Game1(); +game.Run(); diff --git a/src/app.manifest b/src/app.manifest new file mode 100644 index 0000000..e82317a --- /dev/null +++ b/src/app.manifest @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true/pm + permonitorv2,permonitor + + + + diff --git a/src/tunnet.csproj b/src/tunnet.csproj new file mode 100644 index 0000000..06680d2 --- /dev/null +++ b/src/tunnet.csproj @@ -0,0 +1,33 @@ + + + WinExe + net9.0 + Major + false + false + + + app.manifest + Icon.ico + + + + + + + + Icon.ico + + + Icon.bmp + + + + + + + + + + + \ No newline at end of file diff --git a/tunnet.sln b/tunnet.sln new file mode 100644 index 0000000..aa36c25 --- /dev/null +++ b/tunnet.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tunnet", "src/tunnet.csproj", "{728D0B55-232F-4C2B-A31F-04EA4BFF4209}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {728D0B55-232F-4C2B-A31F-04EA4BFF4209}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {728D0B55-232F-4C2B-A31F-04EA4BFF4209}.Debug|Any CPU.Build.0 = Debug|Any CPU + {728D0B55-232F-4C2B-A31F-04EA4BFF4209}.Release|Any CPU.ActiveCfg = Release|Any CPU + {728D0B55-232F-4C2B-A31F-04EA4BFF4209}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal