Compare commits
42
Commits
release002
...
networking
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23fef6f349 | ||
|
|
28c6e83eda | ||
|
|
075750442f | ||
|
|
931236bec0 | ||
|
|
297bd7377f | ||
|
|
5e9a663812 | ||
|
|
66e93d46f4 | ||
|
|
71c654e5b6 | ||
|
|
570f051281 | ||
|
|
0240721d46 | ||
|
|
e350ec26ac | ||
|
|
96e748715b | ||
|
|
d5ef126264 | ||
|
|
9b71ee447a | ||
|
|
d38a75ea72 | ||
|
|
9fa120d4ad | ||
|
|
ea8f64c940 | ||
|
|
c9c6b7e7fb | ||
|
|
a11c4614ea | ||
|
|
5cbe7a345e | ||
|
|
2add42c1cb | ||
|
|
4039c24372 | ||
|
|
7df68febca | ||
|
|
5ecf5fb9d7 | ||
|
|
c3f449b999 | ||
|
|
8a0a8390b2 | ||
|
|
d39f5ca68b | ||
|
|
1c20333f30 | ||
|
|
1d8e103690 | ||
|
|
4c9ecb31d8 | ||
|
|
2e749ed26e | ||
|
|
fc93eb6680 | ||
|
|
5b21ba615e | ||
|
|
02ba86331b | ||
|
|
6a79e8e41e | ||
|
|
6406c4f258 | ||
|
|
9f812f0318 | ||
|
|
adf9871861 | ||
|
|
825a56a4a4 | ||
|
|
e5e3d7bb28 | ||
|
|
e773b51985 | ||
|
|
0975f3b9cd |
No files matched your search
@@ -5,3 +5,6 @@
|
||||
*.wav filter=lfs diff=lfs merge=lfs -text
|
||||
*.ogg filter=lfs diff=lfs merge=lfs -text
|
||||
*.mp3 filter=lfs diff=lfs merge=lfs -text
|
||||
*.bin filter=lfs diff=lfs merge=lfs -text
|
||||
*.dll filter=lfs diff=lfs merge=lfs -text
|
||||
*.so filter=lfs diff=lfs merge=lfs -text
|
||||
+6
-1
@@ -408,4 +408,9 @@ public
|
||||
web_resources/
|
||||
pc_resources/
|
||||
resources_hd/
|
||||
web_resources_x2/
|
||||
web_resources_x2/
|
||||
android_resources/
|
||||
|
||||
.artifacts/
|
||||
|
||||
*.zip
|
||||
@@ -0,0 +1,502 @@
|
||||
# Game State Architecture
|
||||
|
||||
## Purpose
|
||||
|
||||
The game separates authoritative gameplay state from rendering and runtime
|
||||
resources. The same snapshot-and-command boundary supports the in-process
|
||||
single-player server and a WebSocket deterministic-lockstep client/server.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
The architecture has six layers:
|
||||
|
||||
1. `GameState` is the aggregate root for persistent, authoritative state.
|
||||
2. `InternalGameServer` owns `GameState`, advances the local simulation, handles commands, and produces immutable snapshots.
|
||||
3. `ClientLocationState` owns per-client `LocationLocalState` records, including camera orientation. Graphical hosts own this state; it is never replicated.
|
||||
4. Runtime objects hold rendering resources. `Character` and `Location` read immutable server snapshots by stable ID, while `InteractiveObject` still uses a transitional non-owning binding to server-owned state. `Location` also translates local input, scripts, and collision results into semantic server commands.
|
||||
5. Client-facing systems such as `MenuManager` read immutable snapshots and submit typed commands through `IGameServer`.
|
||||
6. Protocol-v2 WebSocket hosts assign preconfigured player slots and exchange
|
||||
one initial state followed by ordered 100 ms tick bundles.
|
||||
|
||||
```text
|
||||
Input / UI
|
||||
| typed GameCommand
|
||||
v
|
||||
IGameServer
|
||||
|
|
||||
v
|
||||
InternalGameServer ---- owns ----> GameState
|
||||
| |
|
||||
| update | stable state objects
|
||||
v v
|
||||
Location / Character / InteractiveObject runtime
|
||||
|
|
||||
v
|
||||
Renderer
|
||||
|
||||
IGameServer ---- immutable GameSnapshot ----> UI and other clients
|
||||
```
|
||||
|
||||
## Authoritative State Model
|
||||
|
||||
### `GameState`
|
||||
|
||||
`GameState` is the top-level state object. It contains:
|
||||
|
||||
- Campaign ID and current location ID.
|
||||
- Day, night, dawn, and darklands flags.
|
||||
- A map of campaign-level players keyed by stable player ID.
|
||||
- A map of typed `LocationGameState` records keyed by location ID.
|
||||
- Inventory, money, player-health HUD values, quests, tutorial progress, chat data, taxi state, and script-global values.
|
||||
|
||||
Live `Location` pointers and rendering objects are no longer stored in `GameState`.
|
||||
Embedded state models such as `Inventory` and `QuestJournal` contain only value
|
||||
data and deterministic operations; they do not retain runtime callbacks.
|
||||
|
||||
### Campaign-level players
|
||||
|
||||
Player `CharacterState` objects are stored in `GameState::players`. The current single-player game uses the ID `"player"`.
|
||||
|
||||
The player state is no longer owned by a `Character` or duplicated as a separately authoritative state for each loaded location. This permits additional player IDs to be introduced later without changing the aggregate ownership model.
|
||||
|
||||
Every player, including the one controlled by the current client, remains in this
|
||||
same authoritative collection. `IGameServer::localPlayerId()` identifies which
|
||||
entry is local to a particular client connection; it is not a separate state
|
||||
object.
|
||||
|
||||
`LocationGameState` does not retain a player pointer or back-reference to `GameState`.
|
||||
Its update boundary receives `GameState::players` by reference, allowing character
|
||||
lookup and simulation to treat every campaign player by stable ID.
|
||||
|
||||
### `LocationGameState`
|
||||
|
||||
Each location record owns:
|
||||
|
||||
- One `LocationNetworkState`.
|
||||
- NPC `CharacterState` objects keyed by configured ID.
|
||||
- `InteractiveObjectState` objects keyed by configured ID.
|
||||
- Trigger-zone enabled/inside flags.
|
||||
- Teleport-zone active flags.
|
||||
- Serialized dialogue runtime state.
|
||||
- Serialized Lua runtime globals.
|
||||
|
||||
World-mode flags (`darklands`, `night`, and `dawn`) exist only at the aggregate
|
||||
`GameState` level. Location rendering and scripts read those values from the
|
||||
top-level snapshot rather than maintaining per-location mirrors.
|
||||
|
||||
State objects use `shared_ptr` internally to keep addresses stable for the
|
||||
remaining local runtime bindings. These pointers never appear in public snapshots.
|
||||
|
||||
### Stable identity
|
||||
|
||||
- Locations use campaign configuration IDs.
|
||||
- Players use keys from `GameState::players`.
|
||||
- NPCs use required location-local configuration IDs.
|
||||
- Interactive objects use required location-local configuration IDs.
|
||||
- Trigger and teleport zones use their configured IDs.
|
||||
|
||||
Missing, empty, duplicate, and reserved IDs are content errors. Runtime references,
|
||||
Lua APIs, snapshots, and persistence all use these IDs rather than configuration
|
||||
array positions.
|
||||
|
||||
## Server Interface
|
||||
|
||||
`IGameServer` is the public state boundary. It exposes:
|
||||
|
||||
- `snapshot()` for an immutable, revisioned `GameSnapshot`.
|
||||
- `submit()` for typed `GameCommand` values.
|
||||
- `update()` for advancing a local fixed tick or polling a remote implementation.
|
||||
- `save()` and `load()` for server-side persistence.
|
||||
|
||||
No public method returns a mutable state pointer or reference.
|
||||
|
||||
### Snapshots
|
||||
|
||||
`GameSnapshot` and its nested snapshot types are value-only read models. They contain no renderer objects, runtime `Location` pointers, mutable references, or active callbacks.
|
||||
|
||||
Snapshots include:
|
||||
|
||||
- Campaign and world-mode state.
|
||||
- All players.
|
||||
- Locations, NPCs, interactive objects, triggers, and teleports.
|
||||
- Inventory item IDs.
|
||||
- Quest views.
|
||||
- Tutorial, chat, taxi, money, and health data.
|
||||
- Script-global values.
|
||||
|
||||
Snapshots have a monotonically increasing revision. `InternalGameServer` caches the current immutable snapshot and rebuilds it only after the authoritative state changes.
|
||||
|
||||
### Commands
|
||||
|
||||
`GameCommand` is a C++17 `std::variant` of semantic command types. Current commands cover:
|
||||
|
||||
- World mode and current location.
|
||||
- Player health and money.
|
||||
- Tutorial progression and flags.
|
||||
- Chat history and unread state.
|
||||
- Taxi state.
|
||||
- Inventory additions and removals.
|
||||
- Quest status, objective completion/visibility, and active-objective changes.
|
||||
- Script globals.
|
||||
- Character transforms, attack targets, navigation destinations, stopping,
|
||||
facing, replanning, health, damage, death reset, attack combos, and animation
|
||||
metadata.
|
||||
- Interactive-object activation.
|
||||
- Trigger-zone state.
|
||||
- Quest-definition reloads.
|
||||
|
||||
The remote implementation currently serializes only
|
||||
`SetCharacterDestinationCommand` as player intent. The server derives the
|
||||
character and location from the assigned connection slot; arbitrary state
|
||||
mutation commands are not accepted from the network.
|
||||
|
||||
### Presentation events
|
||||
|
||||
`IGameServer::drainEvents()` returns value-only events produced by successful
|
||||
authoritative mutations. Inventory add/remove and quest unlock/complete/fail/
|
||||
objective-complete events contain stable IDs only. `Game` drains these events and
|
||||
performs local tutorial, toast, and audio presentation through `MenuManager`.
|
||||
Loading and persistence restoration clear pending events and remain silent.
|
||||
|
||||
## Internal Server
|
||||
|
||||
`InternalGameServer` is the current `IGameServer` implementation. It:
|
||||
|
||||
- Exclusively owns the aggregate `GameState`.
|
||||
- Executes typed commands against authoritative state.
|
||||
- Advances the active location simulation in exact 100 ms ticks.
|
||||
- Builds and caches immutable snapshots.
|
||||
- Delegates save/load serialization to the aggregate state model.
|
||||
|
||||
`LocalGameServerHost` is the graphical client's integration adapter. It owns loaded
|
||||
runtime `Location` objects, forwards simulation events to them, and synchronizes
|
||||
dialogue, Lua, trigger, and teleport auxiliary state. `Game` uses the explicit
|
||||
`IGameServerHost` lifecycle interface and is no longer a friend of
|
||||
`InternalGameServer`. The standalone server does not compile this adapter.
|
||||
|
||||
Location loading has two phases. `LocationContentLoader` parses renderer-free
|
||||
`LocationDefinition` data, and `LocationGameState::setup()` creates/reconciles
|
||||
authoritative NPC, interactive-object, navigation, taxi, trigger, teleport, and
|
||||
animation state. The graphical `Location::setup()` runs afterward and only builds
|
||||
presentation objects from that definition and the prepared state. Lua and dialogue
|
||||
runtime behavior remains client-side.
|
||||
|
||||
### Animation and combat
|
||||
|
||||
Logical animation frame clocks live in `CharacterState`. The renderer-free content
|
||||
loader reads animation frame metadata before authoritative entities are created.
|
||||
Runtime `Character` construction only loads models for presentation and does not
|
||||
submit metadata mutations back to the server.
|
||||
|
||||
`CharacterState::update()` returns value-only events containing arrival Lua function
|
||||
names, attack impacts, navigation requests, and death-animation completion.
|
||||
`LocationGameState` applies queued damage after every character has advanced.
|
||||
Navigation replans are consumed by `InternalGameServer` as deterministic
|
||||
simulation consequences rather than being resubmitted by presentation code.
|
||||
Runtime `Character` objects only pose loaded models and produce audio, particles,
|
||||
and presentation callbacks.
|
||||
|
||||
### Character state operations
|
||||
|
||||
Gameplay operations mutate the authoritative `CharacterState`, not the runtime
|
||||
`Character`:
|
||||
|
||||
- `setTarget()` normalizes the destination, avoids redundant requests, stores the
|
||||
optional Lua arrival function name, and asks the authoritative `LocationNetworkState` to
|
||||
call `planPathExceptMyself()`.
|
||||
- `forceReplan()` recalculates the current requested destination using the same
|
||||
location navigation state.
|
||||
- `stopInPlace()` clears navigation and any pending arrival function.
|
||||
- `stopAndRotateToTarget()`, `resetPlayerAfterDeath()`, `setHp()`, and
|
||||
`tryAttackCombo()` update their respective state directly.
|
||||
|
||||
`InternalGameServer::submit()` resolves the character and location, then invokes
|
||||
these operations for the corresponding semantic command. The runtime `Location`
|
||||
provides convenience methods for submitting those commands from input, scripts,
|
||||
collision handling, and presentation-event processing.
|
||||
|
||||
## Runtime and Visual Object Bindings
|
||||
|
||||
Runtime visual objects do not own their authoritative state objects.
|
||||
|
||||
- `Location` keeps its `IGameServer` reference, stable location ID, and a shared
|
||||
`LocationLocalState` supplied by the graphical host. It resolves its immutable
|
||||
`LocationNetworkState` view from `IGameServer::snapshot()`, while rendering and
|
||||
camera input access the local state directly.
|
||||
- `Character` keeps only its `IGameServer` reference plus stable entity and location IDs. It resolves the player-first character view from `IGameServer::snapshot()`.
|
||||
- `InteractiveObject` keeps a private non-owning reference to its `InteractiveObjectState`; its configured object name is its stable ID.
|
||||
|
||||
`Character::stateSnapshot()` and `Location::stateSnapshot()` return aliasing
|
||||
`shared_ptr` views. Each pointer addresses a state copy inside a `GameSnapshot`,
|
||||
while shared ownership keeps that whole immutable snapshot alive. Update, input,
|
||||
editor, and draw operations capture one such pointer and use it consistently
|
||||
throughout the operation. A missing or unloaded entity produces an empty pointer
|
||||
and presentation or input work is skipped.
|
||||
|
||||
The authoritative state objects are owned by `GameState` or `LocationGameState`.
|
||||
The internal server advances them before publishing a new snapshot revision.
|
||||
Runtime input, scripts, and collision handling submit semantic commands that invoke
|
||||
authoritative character and location operations. Location commands cover pending
|
||||
interaction targets, navigation switching and area changes, editor obstacles, and
|
||||
taxi reset. Camera orientation is deliberately not a server command. No
|
||||
whole-location commit command is exposed.
|
||||
|
||||
Navigation target selection, replanning, stopping, facing, death reset, health
|
||||
assignment, and attack-combo clock changes are implemented by `CharacterState`.
|
||||
`Character` no longer exposes gameplay mutation helpers or a generic state mutation
|
||||
callback. Character construction is presentation-only; frame ranges are already
|
||||
present in `CharacterState` after content setup. It focuses on model posing,
|
||||
rendering, audio, particles, and runtime callbacks.
|
||||
|
||||
Death-animation and health-change callbacks remain runtime-only on `Character`.
|
||||
Arrival behavior is represented solely by the serialized Lua function name in
|
||||
`CharacterState`; `Location` resolves and invokes that name through `ScriptEngine`
|
||||
when it consumes the arrival event.
|
||||
|
||||
`Location` owns presentation-only runtime characters for all non-local entries in
|
||||
`GameSnapshot::players`. It reconciles them by stable ID as snapshots change,
|
||||
reuses the local-player assets and animation set, and includes them in all render,
|
||||
shadow, lighting, animation, damage, and name-tag passes. The local entry is
|
||||
excluded using `IGameServer::localPlayerId()` because its visual is already owned
|
||||
by `Game`.
|
||||
|
||||
`GameObjectLoader` now:
|
||||
|
||||
1. Receives immutable object/NPC definitions parsed by `LocationContentLoader`.
|
||||
2. Resolves already-prepared authoritative entities by stable ID.
|
||||
3. Constructs meshes, textures, VBOs, `InteractiveObject`, and `Character`
|
||||
presentation wrappers without creating or overwriting authoritative state.
|
||||
|
||||
Configuration remains the source of visual assets, animation paths, meshes, textures, and fixed tuning data.
|
||||
|
||||
## State Update Flow
|
||||
|
||||
Render frames and simulation ticks are separate:
|
||||
|
||||
1. SDL input and UI presentation use the real elapsed render-frame time.
|
||||
2. A local host accumulates `steady_clock` elapsed time and runs zero or more
|
||||
exact 100 ms simulation ticks. A remote host polls transport every frame but
|
||||
advances only from contiguous server tick messages.
|
||||
3. Commands assigned to tick `N` are applied in server sequence order before
|
||||
simulation tick `N`.
|
||||
4. The server freezes location character observations and updates every player,
|
||||
NPC, taxi, and interactive object with exactly 100 ms. An empty player
|
||||
collection remains valid.
|
||||
5. Attack impacts are queued and applied only after all characters advance.
|
||||
Navigation recovery is applied inside the deterministic state path.
|
||||
6. The server invalidates its cached snapshot and advances its revision.
|
||||
7. Runtime locations consume the completed tick's value-only events and perform
|
||||
rendering, audio, particles, and supported presentation callbacks.
|
||||
8. Rendering can occur between ticks and never changes authoritative tick time.
|
||||
|
||||
Commands that update bound character or object state do not reload the whole location. This avoids replaying dialogue-node effects or Lua callbacks.
|
||||
|
||||
## Campaign and Location Lifecycle
|
||||
|
||||
Only one location is normally loaded as a runtime object.
|
||||
|
||||
### Campaign loading
|
||||
|
||||
When a campaign starts:
|
||||
|
||||
- Existing campaign state and runtime locations are cleared.
|
||||
- Quest definitions are loaded.
|
||||
- The graphical single-player host requests a campaign-level `"player"` state and
|
||||
creates its visual wrapper.
|
||||
- A standalone host may deliberately create no players; locations continue to tick.
|
||||
- The battle-zone test bot is an explicit host option rather than an unconditional
|
||||
campaign side effect.
|
||||
|
||||
### Location loading
|
||||
|
||||
When a location is loaded:
|
||||
|
||||
- `LocationContentLoader` parses a renderer-free `LocationDefinition`.
|
||||
- `LocationGameState::setup()` creates or reconciles navigation, taxi, NPC,
|
||||
interactive-object, trigger, teleport, and animation state.
|
||||
- Saved mutable fields are overlaid on configuration defaults by stable ID.
|
||||
- `Location::setup()` builds static and entity visuals from the prepared definition
|
||||
without mutating authoritative state.
|
||||
- The shared campaign player is attached.
|
||||
- Runtime visuals are created for other player IDs currently present in the
|
||||
snapshot and are subsequently spawned or removed as snapshots change.
|
||||
- Dialogue, Lua, trigger/teleport visuals, and presentation callbacks are initialized.
|
||||
- The runtime `Location` is owned and registered by `LocalGameServerHost`;
|
||||
`InternalGameServer` remains headless.
|
||||
|
||||
### Location unloading
|
||||
|
||||
When leaving a location:
|
||||
|
||||
- Auxiliary runtime state is captured.
|
||||
- The visual/runtime `Location` is destroyed.
|
||||
- Its typed `LocationGameState` remains in `GameState`.
|
||||
|
||||
The player state remains campaign-level and survives location changes.
|
||||
|
||||
## Save and Load Schema
|
||||
|
||||
Authoritative persistence uses one strict, versioned schema. `schemaVersion` is
|
||||
required and unsupported versions are rejected rather than migrated. A
|
||||
single-player save is a separate versioned envelope containing `networkState`
|
||||
(the authoritative `GameState` JSON) and `localState` (the client-local location
|
||||
map). Lockstep sends that authoritative document only in `initial_state`; later
|
||||
messages contain numbered command bundles.
|
||||
|
||||
- Campaign players are stored once in an ID-keyed `players` object.
|
||||
- Locations are keyed by location ID.
|
||||
- Each location stores NPC and interactive-object state in ID-keyed objects.
|
||||
- Pending interaction targets and character references use stable IDs.
|
||||
- Immutable content such as meshes, initial taxi configuration, and object
|
||||
definitions is reconstructed from campaign configuration.
|
||||
- Configuration is loaded first and mutable saved state is overlaid in place.
|
||||
Snapshot-backed runtime objects then resolve the resulting state by stable ID.
|
||||
|
||||
Old user save slots are intentionally unsupported. Bundled start-state snapshots
|
||||
must be regenerated with `Game::saveInitialState()` whenever the schema changes.
|
||||
|
||||
## UI, Scripts, Dialogue, and Quests
|
||||
|
||||
### UI
|
||||
|
||||
`MenuManager` no longer holds `GameState&` or a mutable `Inventory*`.
|
||||
|
||||
It now:
|
||||
|
||||
- Reads inventory, quests, tutorial state, chat, money, health, location, and world mode from `GameSnapshot`.
|
||||
- Submits typed commands for mutations.
|
||||
- Continues to own presentation-only UI trees, screen state, textures, and callbacks.
|
||||
|
||||
### Scripts
|
||||
|
||||
Lua remains an in-process single-player runtime. Character, inventory, quest, and
|
||||
campaign-global bindings submit semantic commands through `Location`; the server
|
||||
invokes operations on centrally owned state. Snapshot queries provide global
|
||||
values, inventory counts, item presence, and synchronous quest validation for the
|
||||
existing Lua API. NPC,
|
||||
interactive-object, trigger-zone, and teleport-zone bindings address entities by
|
||||
configured ID. Other object and global-state bindings remain trusted local
|
||||
integrations.
|
||||
|
||||
Each location script registers initialization, enter, and exit callbacks.
|
||||
Initialization runs only when the location has no retained state; loading the Lua
|
||||
file again for rendering does not repeat state-resetting setup. Enter and exit
|
||||
callbacks continue to run for every location transition.
|
||||
|
||||
The scalar Lua runtime state for each location is stored under `LocationGameState::scriptGlobals`. Multiplayer location scripts are expected to be empty, so remote script execution is intentionally outside the current scope.
|
||||
|
||||
### Dialogue and cutscenes
|
||||
|
||||
Dialogue runtime state is captured in each `LocationGameState`. Dialogue global
|
||||
flags use snapshot getter and command setter callbacks rather than retaining a
|
||||
mutable map pointer. Dialogue and cutscene rendering remain local presentation
|
||||
systems.
|
||||
|
||||
Dialogues and cutscenes are outside the planned multiplayer gameplay mode, but their existing single-player save and callback behavior is retained.
|
||||
|
||||
### Quests, inventory, and tutorial
|
||||
|
||||
These callback-free state systems remain part of `GameState` for single-player
|
||||
compatibility. UI access, mutations, and presentation notifications cross the
|
||||
server interface. They can remain empty or disabled in multiplayer mode as planned.
|
||||
|
||||
## Multiplayer Lockstep
|
||||
|
||||
Protocol v2 uses server-sequenced deterministic lockstep:
|
||||
|
||||
- The server assigns a connection to a preconfigured campaign player slot.
|
||||
- Connection receives one authoritative state at a completed tick plus its
|
||||
assigned player ID, tick duration, input delay, and compatibility fingerprint.
|
||||
- Destination input is normalized and scheduled two ticks in the future.
|
||||
- The server broadcasts every numbered tick, including empty ticks. Clients
|
||||
buffer out-of-order messages and advance only contiguous tick IDs.
|
||||
- All replicas apply the same globally sequenced commands before one exact
|
||||
100 ms update.
|
||||
- Post-tick canonical hashes exclude persistence timestamps and local
|
||||
presentation state. A mismatch is diagnosed but not automatically repaired.
|
||||
|
||||
No wall-clock timestamp participates in simulation. `steady_clock` paces the
|
||||
server and local render accumulator only, so different machine clocks do not
|
||||
affect command placement or state. The current missing-packet policy is to stall;
|
||||
there is no prediction or rollback.
|
||||
|
||||
Current boundaries remain:
|
||||
|
||||
- only `SetCharacterDestinationCommand` crosses the network;
|
||||
- player characters must already exist in the initial state and campaign slot
|
||||
list; dynamic spawning and reconnect history are not implemented;
|
||||
- authentication and automatic checkpoint resynchronization are absent;
|
||||
- multiplayer Lua/dialogue shared behavior is unsupported;
|
||||
- deterministic compatibility targets identical executable and content builds.
|
||||
Floating-point simulation is not guaranteed bit-identical across platforms.
|
||||
|
||||
## Platform Build Integration
|
||||
|
||||
The new state and server files are registered in:
|
||||
|
||||
- `proj-windows/CMakeLists.txt`
|
||||
- `proj-linux/CMakeLists.txt`
|
||||
- `proj-web/CMakeLists.txt`
|
||||
- `proj-android/app/jni/src/CMakeLists.txt`
|
||||
|
||||
The refactor uses portable C++17 and introduces no Windows-only gameplay code.
|
||||
|
||||
The standalone target lives under `server/`. It links the authoritative state,
|
||||
campaign, content-definition, and portable resource sources only; SDL, OpenGL,
|
||||
audio, Lua, dialogue presentation, and rendering sources are absent. It can prepare
|
||||
a selected campaign/location with zero players. The Windows server adds
|
||||
Boost.Beast transport and runs a fixed 100 ms lockstep loop; other platforms
|
||||
continue to compile the portable state core without that transport.
|
||||
|
||||
The Windows Debug target was verified with:
|
||||
|
||||
```powershell
|
||||
cmake --build proj-windows/build --config Debug --target ShadowOverBishkekDemo -- /m
|
||||
```
|
||||
|
||||
## Important Constraints
|
||||
|
||||
- Runtime C++ callbacks are not part of `CharacterState` or public snapshots;
|
||||
serializable Lua arrival function names are state data.
|
||||
- `InteractiveObjectState` animation callbacks are also removed from public snapshots.
|
||||
- Character target and attacker references use stable IDs (`"player"` or a unique
|
||||
location-local NPC ID).
|
||||
- Some top-level values remain mirrors for compatibility, notably player health used by the HUD and scripts.
|
||||
- Dialogue and Lua are synchronized as auxiliary location state rather than fully networked subsystems.
|
||||
- `IGameServerLifecycle` is the graphics-free campaign/location administration
|
||||
boundary. `LocalGameServerHost` adds client-only runtime construction and
|
||||
auxiliary-state synchronization without making `Game` a server friend.
|
||||
- Empty player maps are valid. Player-specific interactions remain inactive until
|
||||
a player entity is added.
|
||||
- Pathfinding priority queues use cell index as a stable secondary key.
|
||||
- Gameplay randomness must be seeded and serialized; the `random_device` battle
|
||||
bot is disabled for multiplayer sessions.
|
||||
- A lockstep compatibility fingerprint must match before the client accepts the
|
||||
initial state.
|
||||
|
||||
## Main Files
|
||||
|
||||
- `src/GameState.h` / `src/GameState.cpp` — aggregate state and top-level persistence.
|
||||
- `src/LocationState.h` / `src/LocationState.cpp` — separate local camera and authoritative network location records, plus single-player persistence composition.
|
||||
- `src/LocationGameState.h` / `src/LocationGameState.cpp` — authoritative typed location state, simulation, and ID-keyed persistence.
|
||||
- `src/content/LocationDefinition.h` / `.cpp` — renderer-free content definitions,
|
||||
parsing, and animation metadata loading.
|
||||
- `src/game_server/IGameServer.h` — public snapshot and command contract.
|
||||
- `src/game_server/IGameServerLifecycle.h` — graphics-free campaign/location lifecycle.
|
||||
- `src/game_server/InternalGameServer.h` / `.cpp` — in-process authoritative implementation.
|
||||
- `src/game_server/LocalGameServerHost.h` / `.cpp` — graphical-client runtime adapter.
|
||||
- `src/game_server/NetworkProtocol.h` / `.cpp` — protocol-v2 messages,
|
||||
lockstep timeline, validation, and canonical hashes.
|
||||
- `src/game_server/WebsocketGameServer.h` / `.cpp` and
|
||||
`WebsocketGameClient.h` / `.cpp` — slot assignment, input scheduling, tick
|
||||
broadcasting, buffering, and replica advancement.
|
||||
- `src/Game.h` / `src/Game.cpp` — application host, campaign lifecycle, and runtime wiring.
|
||||
- `src/Location.h` / `src/Location.cpp` — loaded location runtime, command routing,
|
||||
interactions, collisions, scripts, and presentation-event consumption.
|
||||
- `src/Character.h` / `src/Character.cpp` — passive character presentation resolving
|
||||
immutable `CharacterState` snapshots by stable ID.
|
||||
- `src/CharacterState.h` / `src/CharacterState.cpp` — deterministic character
|
||||
simulation, navigation operations, combat state, and logical animation clock.
|
||||
- `src/items/InteractiveObject.h` / `.cpp` — visual object runtime bound to central object state.
|
||||
- `src/items/GameObjectLoader.h` / `.cpp` — presentation builders for prepared definitions.
|
||||
- `src/MenuManager.h` / `src/MenuManager.cpp` — snapshot-driven UI and command submission.
|
||||
@@ -184,4 +184,45 @@ make -j$(nproc) -C build #Компилируем
|
||||
|
||||
Для постройки без звука
|
||||
rm -rf build #Очищаем build папку
|
||||
cmake -B build -DAUDIO=1 #Пересоздаём конфигурацию CMake
|
||||
cmake -B build -DAUDIO=1 #Пересоздаём конфигурацию CMake
|
||||
|
||||
|
||||
# Cmake Build NSIS and Portable for Windows:
|
||||
|
||||
```
|
||||
cmake --build . --config Release
|
||||
cpack -C Release
|
||||
```
|
||||
|
||||
Если есть такая ошибка:
|
||||
|
||||
CPack Error: Cannot find NSIS compiler makensis: likely it is not installed, or not in your PATH
|
||||
CPack Error: Could not read NSIS registry value. This is usually caused by NSIS not being installed. Please install NSIS from http://nsis.sourceforge.net
|
||||
CPack Error: Cannot initialize the generator NSIS
|
||||
|
||||
|
||||
То нужно установить nsis отсюда: https://nsis.sourceforge.io/Download
|
||||
|
||||
|
||||
# Steam windows
|
||||
|
||||
```
|
||||
cmake -DSTEAMSDK=ON ..
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
|
||||
# Steam Linux
|
||||
|
||||
```
|
||||
docker run -it --rm -v "${PWD}:/work2" -w /work2 registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest bash
|
||||
|
||||
|
||||
apt-get update
|
||||
apt-get install libboost-dev libeigen3-dev liblua5.4-dev libzip-dev libglu1-mesa-dev
|
||||
|
||||
|
||||
cmake -DSTEAMSDK=ON -DCMAKE_BUILD_TYPE=Release ..
|
||||
cmake --build . -j 4
|
||||
|
||||
```
|
||||
@@ -0,0 +1,176 @@
|
||||
# WebSocket Deterministic Lockstep Networking
|
||||
|
||||
## Scope
|
||||
|
||||
The Windows WebSocket transport uses Boost.Asio and Boost.Beast to run a
|
||||
server-sequenced deterministic lockstep simulation. A client receives one
|
||||
authoritative state at a completed tick boundary. After that, the server sends
|
||||
only numbered tick messages containing ordered player commands (or an empty
|
||||
command list).
|
||||
|
||||
The current command surface is intentionally limited to
|
||||
`SetCharacterDestinationCommand`.
|
||||
|
||||
## Runtime Architecture
|
||||
|
||||
### Server
|
||||
|
||||
`WebsocketGameServer` wraps the headless `InternalGameServer`.
|
||||
|
||||
- The simulation tick is fixed at 100 ms.
|
||||
- Each accepted connection is assigned the first free character ID from the
|
||||
campaign's `networkPlayerSlots`; the connection is rejected when all slots
|
||||
are occupied.
|
||||
- The initial message contains the state, completed snapshot tick, assigned
|
||||
player ID, tick duration, two-tick input delay, and compatibility fingerprint.
|
||||
- Destination inputs cross from the Asio thread through a queue. The simulation
|
||||
thread validates client sequence numbers, replaces client identity with the
|
||||
assigned slot, and schedules commands two ticks in the future.
|
||||
- Every tick is broadcast, including ticks with no commands. No periodic state
|
||||
snapshots are sent.
|
||||
|
||||
### Client
|
||||
|
||||
`WebsocketGameClient` implements `IGameServer`.
|
||||
|
||||
- It connects asynchronously to `ws://127.0.0.1:8080/`.
|
||||
- Received messages are queued by the network thread and applied on the game
|
||||
thread from `update()`.
|
||||
- It maintains an internal `InternalGameServer` replica so existing snapshot
|
||||
consumers and transitional runtime-state bindings continue to work.
|
||||
- Camera orientation lives in host-owned `LocationLocalState`, so incoming
|
||||
authoritative snapshots cannot overwrite camera movement.
|
||||
- `submit()` serializes destination intent only. Other command variants remain
|
||||
local no-ops for a remote connection.
|
||||
- Tick bundles are buffered by ID. The replica advances only while the next
|
||||
contiguous tick is available, applying its commands before one exact 100 ms
|
||||
simulation step.
|
||||
- Completed simulation events are passed to the runtime `Location` for
|
||||
presentation, and ordinary server events are drainable through `IGameServer`.
|
||||
- Client-side save and load calls are ignored because persistence remains
|
||||
server-side.
|
||||
|
||||
`RemoteGameServerHost` prepares local presentation resources and runtime
|
||||
locations against the replica and presents completed-tick events. It never
|
||||
advances simulation from a render-frame delta.
|
||||
|
||||
## Campaign Routing
|
||||
|
||||
The graphical game uses stable router objects for `IGameServer` and
|
||||
`IGameServerHost`, allowing existing UI and runtime references to remain valid.
|
||||
|
||||
When `NETWORK` is defined:
|
||||
|
||||
- `battle_zone_multiplayer` uses `WebsocketGameClient` and `RemoteGameServerHost`.
|
||||
- `main`, `battle_zone`, and every other campaign use `InternalGameServer` and
|
||||
`LocalGameServerHost`.
|
||||
|
||||
The WebSocket client is created only when `battle_zone_multiplayer` is selected
|
||||
and is destroyed when that campaign is unloaded. The single-player and
|
||||
multiplayer Battle Zone entries share location content and the start-state path,
|
||||
so the state can be regenerated through the single-player entry. At startup, the
|
||||
standalone server loads the authoritative half of that shared save and rewrites
|
||||
its campaign ID to `battle_zone_multiplayer`; each remote client restores only
|
||||
the local presentation half. The multiplayer campaign currently declares the
|
||||
pre-existing `player` and `player2` state entries as connection
|
||||
slots; the random test-bot controller is disabled.
|
||||
The campaign's `networkCompatibility` token is the fingerprint; release builds
|
||||
must bump it whenever deterministic content changes.
|
||||
|
||||
If DNS resolution, TCP connection, the WebSocket handshake, or the active socket
|
||||
fails, the client unloads the remote campaign and returns to the campaign
|
||||
selection screen.
|
||||
|
||||
## JSON Protocol v2
|
||||
|
||||
Every message uses a versioned JSON envelope:
|
||||
|
||||
```json
|
||||
{
|
||||
"protocolVersion": 2,
|
||||
"type": "tick",
|
||||
"payload": {
|
||||
"tickId": 81,
|
||||
"commands": [],
|
||||
"stateHash": "0123456789abcdef"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Message types are:
|
||||
|
||||
- `initial_state` (server to client): one state snapshot and lockstep metadata;
|
||||
- `destination_input` (client to server): monotonic client sequence and a
|
||||
centimetre-normalized finite target;
|
||||
- `tick` (server to client): tick ID, globally sequenced commands, and
|
||||
post-tick diagnostic state hash;
|
||||
- `error` (server to client): invalid input, incompatibility, or full server.
|
||||
|
||||
Protocol v1 is not compatible. Malformed payloads, non-finite or out-of-range
|
||||
coordinates, duplicate client sequences, and unsupported commands cannot enter
|
||||
the authoritative command stream.
|
||||
|
||||
WebSocket ordering is not used as simulation time. Integer tick IDs are the
|
||||
only authoritative clock. The server uses `steady_clock` only to pace its loop,
|
||||
and clients may have different wall clocks without affecting the result. A
|
||||
client stalls on a missing tick instead of predicting or rolling back.
|
||||
|
||||
Single-player persistence remains a separate envelope combining authoritative
|
||||
and client-local state. `savedAt`, camera state, and presentation objects are
|
||||
excluded from the diagnostic deterministic hash.
|
||||
|
||||
## Build Configuration
|
||||
|
||||
Networking is enabled only for Windows:
|
||||
|
||||
- `proj-windows/CMakeLists.txt` defines `NETWORK`, compiles the WebSocket client
|
||||
and remote host, and links `ws2_32` and `mswsock`.
|
||||
- `server/CMakeLists.txt` defines `NETWORK` for the Windows `GameServer`, compiles
|
||||
the WebSocket server, and links the Windows socket libraries.
|
||||
- Linux, Android, and Web builds do not define `NETWORK` and do not compile the
|
||||
network transport.
|
||||
|
||||
The previous Web-build `NETWORK` definition was removed.
|
||||
|
||||
## Running
|
||||
|
||||
Build the server:
|
||||
|
||||
```powershell
|
||||
cmake -S server -B server/build
|
||||
cmake --build server/build --config Debug --target GameServer
|
||||
```
|
||||
|
||||
Run it from the repository root:
|
||||
|
||||
```powershell
|
||||
.\server\build\Debug\GameServer.exe --campaign battle_zone_multiplayer --location uni_exterior
|
||||
```
|
||||
|
||||
The listener defaults to `0.0.0.0:8080`. It can be changed with:
|
||||
|
||||
```text
|
||||
--address IP
|
||||
--port N
|
||||
```
|
||||
|
||||
Launch the Windows game and select `battle_zone_multiplayer`. The client connects to
|
||||
`127.0.0.1:8080`. Selecting another campaign continues to use the local server.
|
||||
|
||||
## Verification
|
||||
|
||||
CTest covers protocol-v2 round trips and validation, input-delay ordering,
|
||||
fixed-tick replica behavior, campaign slot metadata, initial connection and
|
||||
slot assignment, destination submission, and contiguous tick consumption.
|
||||
|
||||
## Current Limitations
|
||||
|
||||
- Only preconfigured player slots can connect; dynamic join/spawn commands are
|
||||
not implemented.
|
||||
- There is no authentication or reconnect/replay history.
|
||||
- A hash mismatch is logged but does not yet trigger checkpoint resynchronization.
|
||||
- The endpoint is hardcoded in the graphical client.
|
||||
- Multiplayer Lua and dialogue behavior remains unsupported.
|
||||
- Determinism is supported for identical executable/content builds. The
|
||||
floating-point simulation is not guaranteed bit-identical across platforms
|
||||
or compilers.
|
||||
@@ -25,7 +25,7 @@ macro(check_and_download URL ARCHIVE_NAME EXTRACTED_DIR_NAME CHECK_FILE)
|
||||
endmacro()
|
||||
|
||||
# 1) ZLIB (Нужна только для инклудов, если не используете emscripten порты)
|
||||
check_and_download("https://www.zlib.net/zlib132.zip" "zlib132.zip" "zlib-1.3.2" "CMakeLists.txt")
|
||||
check_and_download("https://github.com/madler/zlib/releases/download/v1.3.2/zlib132.zip" "zlib132.zip" "zlib-1.3.2" "CMakeLists.txt")
|
||||
|
||||
# 2) SDL2
|
||||
check_and_download("https://github.com/libsdl-org/SDL/archive/refs/tags/release-2.32.10.zip" "release-2.32.10.zip" "SDL-release-2.32.10" "CMakeLists.txt")
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
optimize_web_resources.py - Resize PNG images for the web build.
|
||||
|
||||
Copies <src> to <dst>/resources/, then downscales all PNG files:
|
||||
- resources/w/ui/img/** -> 1/8 original size
|
||||
- all other PNGs -> 1/4 original size
|
||||
|
||||
Files listed in EXCEPTIONS are copied unchanged.
|
||||
|
||||
Usage (manual):
|
||||
python optimize_web_resources.py [--src resources] [--dst web_resources]
|
||||
|
||||
Usage (CMake):
|
||||
${Python3_EXECUTABLE} optimize_web_resources.py --src <abs_src> --dst <abs_dst>
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import shutil
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
raise SystemExit("Pillow is required: pip install Pillow")
|
||||
|
||||
# Paths relative to the resources directory — these files are never resized.
|
||||
EXCEPTIONS = {
|
||||
"loading.png",
|
||||
"loading_land003_en.png",
|
||||
"loading_land003_ru.png",
|
||||
"black.png",
|
||||
"transparent.png",
|
||||
"w/blue.png",
|
||||
"w/red.png",
|
||||
"w/spark.png",
|
||||
"w/star.png",
|
||||
"w/star_red.png",
|
||||
"w/white.png",
|
||||
"w/ui/img/main/aboutPage003android.png",
|
||||
"w/ui_en/img/main/aboutPage003android.png",
|
||||
"w/exterior/texAtlas002.png",
|
||||
}
|
||||
|
||||
# Path prefixes (relative to resources root, forward-slash) that get 8x reduction.
|
||||
HIGH_REDUCTION_PREFIXES = (
|
||||
"w/ui/img",
|
||||
)
|
||||
|
||||
LOW_REDUCTION_POSTFIXES = (
|
||||
"texAtlas002.png",
|
||||
"Building_work014.png",
|
||||
"Building_Floors_tex004.png",
|
||||
"Building_Walls_tex006.png",
|
||||
"asphalt003small.png",
|
||||
"Ext_Building004.png",
|
||||
"Plane3_tex002.png",
|
||||
"darklands_building002.png",
|
||||
"Staircase001.png",
|
||||
"Staircase_Obj002.png"
|
||||
)
|
||||
|
||||
def _resize_factor(rel: str) -> int:
|
||||
norm = rel.replace("\\", "/")
|
||||
for prefix in HIGH_REDUCTION_PREFIXES:
|
||||
if norm.startswith(prefix):
|
||||
return 8
|
||||
for prefix in LOW_REDUCTION_POSTFIXES:
|
||||
if norm.endswith(prefix):
|
||||
return 2
|
||||
return 4
|
||||
|
||||
|
||||
def _next_pot(n: int) -> int:
|
||||
if n < 1:
|
||||
return 1
|
||||
p = 1
|
||||
while p < n:
|
||||
p <<= 1
|
||||
return p
|
||||
|
||||
|
||||
def optimize(src_dir: str, dst_parent: str) -> None:
|
||||
src_dir = os.path.abspath(src_dir)
|
||||
dst_resources = os.path.join(os.path.abspath(dst_parent), "resources")
|
||||
|
||||
print(f"Copying {src_dir} -> {dst_resources}")
|
||||
if os.path.exists(dst_resources):
|
||||
shutil.rmtree(dst_resources)
|
||||
shutil.copytree(src_dir, dst_resources)
|
||||
|
||||
total = 0
|
||||
for root, _dirs, files in os.walk(dst_resources):
|
||||
for filename in files:
|
||||
if not filename.lower().endswith(".png"):
|
||||
continue
|
||||
|
||||
full_path = os.path.join(root, filename)
|
||||
rel = os.path.relpath(full_path, dst_resources).replace("\\", "/")
|
||||
|
||||
if rel in EXCEPTIONS:
|
||||
print(f" skip (exception): {rel}")
|
||||
continue
|
||||
|
||||
factor = _resize_factor(rel)
|
||||
|
||||
with Image.open(full_path) as img:
|
||||
orig_w, orig_h = img.size
|
||||
new_w = _next_pot(max(1, orig_w // factor))
|
||||
new_h = _next_pot(max(1, orig_h // factor))
|
||||
resized = img.resize((new_w, new_h), Image.LANCZOS)
|
||||
resized.save(full_path)
|
||||
|
||||
print(f" {rel}: {orig_w}x{orig_h} -> {new_w}x{new_h} (/{factor} + POT)")
|
||||
total += 1
|
||||
|
||||
print(f"Done. Resized {total} PNG file(s).")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Optimize PNG images for web build")
|
||||
parser.add_argument("--src", default="resources",
|
||||
help="Source resources directory (default: resources)")
|
||||
parser.add_argument("--dst", default="android_resources",
|
||||
help="Destination parent directory; will contain a 'resources' subdir "
|
||||
"(default: android_resources)")
|
||||
args = parser.parse_args()
|
||||
optimize(args.src, args.dst)
|
||||
@@ -27,7 +27,18 @@ except ImportError:
|
||||
# Paths relative to the resources directory — these files are never resized.
|
||||
EXCEPTIONS = {
|
||||
"loading.png",
|
||||
"loading_land003_en.png",
|
||||
"loading_land003_ru.png",
|
||||
"black.png",
|
||||
"transparent.png",
|
||||
"w/blue.png",
|
||||
"w/red.png",
|
||||
"w/spark.png",
|
||||
"w/star.png",
|
||||
"w/star_red.png",
|
||||
"w/white.png",
|
||||
"w/ui/img/main/aboutPage003android.png",
|
||||
"w/ui_en/img/main/aboutPage003android.png"
|
||||
}
|
||||
|
||||
# Path prefixes (relative to resources root, forward-slash) that get 8x reduction.
|
||||
@@ -35,13 +46,28 @@ HIGH_REDUCTION_PREFIXES = (
|
||||
"w/ui/img",
|
||||
)
|
||||
|
||||
LOW_REDUCTION_POSTFIXES = (
|
||||
"texAtlas002.png",
|
||||
"Building_work014.png",
|
||||
"Building_Floors_tex004.png",
|
||||
"Building_Walls_tex006.png",
|
||||
"asphalt003small.png",
|
||||
"Ext_Building004.png",
|
||||
"Plane3_tex002.png",
|
||||
"darklands_building002.png",
|
||||
"Staircase001.png",
|
||||
"Staircase_Obj002.png"
|
||||
)
|
||||
|
||||
def _resize_factor(rel: str) -> int:
|
||||
norm = rel.replace("\\", "/")
|
||||
for prefix in HIGH_REDUCTION_PREFIXES:
|
||||
if norm.startswith(prefix):
|
||||
return 8
|
||||
return 4
|
||||
for prefix in LOW_REDUCTION_POSTFIXES:
|
||||
if norm.endswith(prefix):
|
||||
return 2
|
||||
return 8
|
||||
|
||||
|
||||
def _next_pot(n: int) -> int:
|
||||
|
||||
@@ -61,5 +61,5 @@ app/jni/libpng
|
||||
app/jni/SDL
|
||||
app/jni/zlib
|
||||
|
||||
app/src/main/assets/resources
|
||||
app/src/main/assets
|
||||
|
||||
@@ -1 +1 @@
|
||||
### Перед запуском в папке ```app/jni/```(рядом с src) нужно создать три папки с исходниками библиотек ```libpng```, ```SDL```, ```zlib```
|
||||
### Android version
|
||||
@@ -1,4 +1,4 @@
|
||||
def buildAsLibrary = project.hasProperty('BUILD_AS_LIBRARY');
|
||||
def buildAsLibrary = project.hasProperty('BUILD_AS_LIBRARY')
|
||||
def buildAsApplication = !buildAsLibrary
|
||||
if (buildAsApplication) {
|
||||
apply plugin: 'com.android.application'
|
||||
@@ -9,30 +9,33 @@ else {
|
||||
|
||||
android {
|
||||
if (buildAsApplication) {
|
||||
namespace "org.libsdl.app"
|
||||
namespace "fishrungames.shadowoverbishkek"
|
||||
}
|
||||
compileSdkVersion 34
|
||||
compileSdkVersion 37
|
||||
defaultConfig {
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 34
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 37
|
||||
versionCode 4
|
||||
versionName "1.0.7"
|
||||
externalNativeBuild {
|
||||
/*ndkBuild {
|
||||
arguments "APP_PLATFORM=android-19"
|
||||
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||
}*/
|
||||
cmake {
|
||||
arguments "-DANDROID_APP_PLATFORM=android-19", "-DANDROID_STL=c++_static"
|
||||
cppFlags "-std=c++11 -frtti -fexceptions"
|
||||
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||
arguments /*"-DANDROID_APP_PLATFORM=android-19",*/ "-DANDROID_STL=c++_static"
|
||||
cppFlags "-std=c++17 -frtti -fexceptions"
|
||||
abiFilters 'arm64-v8a', 'x86_64'
|
||||
}
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
// Enables code optimizations.
|
||||
minifyEnabled = true
|
||||
// Enables resource shrinking.
|
||||
shrinkResources = true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
applicationVariants.all { variant ->
|
||||
@@ -62,7 +65,7 @@ android {
|
||||
libraryVariants.all { variant ->
|
||||
variant.outputs.all { output ->
|
||||
if (output.outputFileName != null && output.outputFileName.endsWith(".aar")) {
|
||||
output.outputFileName = "org.libsdl.app.aar"
|
||||
output.outputFileName = "fishrungames.shadowoverbishkek.aar"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,5 +73,6 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.core:core-splashscreen:1.0.1'
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
}
|
||||
@@ -21,7 +21,7 @@ set(TP_ROOT "${THIRDPARTY_DIR}")
|
||||
# ==============================================================================
|
||||
|
||||
# --- ZLIB ---
|
||||
add_subdirectory("${TP_ROOT}/zlib-1.3.1" zlib-build)
|
||||
#add_subdirectory("${TP_ROOT}/zlib-1.3.2" zlib-build)
|
||||
|
||||
# --- LIBPNG ---
|
||||
set(PNG_STATIC ON CACHE BOOL "Build static library" FORCE)
|
||||
@@ -39,6 +39,10 @@ add_subdirectory("${TP_ROOT}/libpng-1.6.51" libpng-build)
|
||||
# --- SDL2 ---
|
||||
# Android-версия SDL требует специфичных настроек, но add_subdirectory обычно подхватывает их сама
|
||||
add_subdirectory("${TP_ROOT}/SDL-release-2.32.10" sdl-build)
|
||||
add_subdirectory("${TP_ROOT}/SDL_mixer-release-2.8.0" sdl-mixer-build)
|
||||
|
||||
|
||||
add_subdirectory("${TP_ROOT}/SDL_ttf-release-2.24.0" sdl-ttf-build)
|
||||
|
||||
# --- LIBZIP ---
|
||||
# Отключаем поиск системных крипто-библиотек, так как в NDK их может не быть в стандартных путях
|
||||
|
||||
@@ -33,62 +33,157 @@ endforeach()
|
||||
# Создаем кастомную цель, которая будет запускать процесс копирования
|
||||
add_custom_target(sync_resources ALL DEPENDS ${RES_OUTPUTS})
|
||||
|
||||
set(LUA_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/lua-5.4.8")
|
||||
file(GLOB LUA_SOURCES "${LUA_SRC_DIR}/*.c")
|
||||
list(REMOVE_ITEM LUA_SOURCES
|
||||
"${LUA_SRC_DIR}/lua.c"
|
||||
"${LUA_SRC_DIR}/luac.c"
|
||||
"${LUA_SRC_DIR}/onelua.c"
|
||||
)
|
||||
add_library(lua_static STATIC ${LUA_SOURCES})
|
||||
target_include_directories(lua_static PUBLIC "${LUA_SRC_DIR}")
|
||||
|
||||
|
||||
|
||||
add_library(main SHARED
|
||||
SDL_android_main.c
|
||||
../../../../src/BoneAnimatedModel.cpp
|
||||
../../../../src/Environment.cpp
|
||||
../../../../src/Game.cpp
|
||||
SDL_android_main.c
|
||||
../../../../src/main.cpp
|
||||
../../../../src/Projectile.cpp
|
||||
../../../../src/SparkEmitter.cpp
|
||||
../../../../src/TextModel.cpp
|
||||
../../../../src/UiManager.cpp
|
||||
../../../../src/utils/Perlin.cpp
|
||||
../../../../src/utils/TaskManager.cpp
|
||||
../../../../src/utils/Utils.cpp
|
||||
../../../../src/navigation/PathFinder.cpp
|
||||
../../../../src/planet/PlanetData.cpp
|
||||
../../../../src/planet/PlanetObject.cpp
|
||||
../../../../src/planet/StoneObject.cpp
|
||||
../../../../src/render/FrameBuffer.cpp
|
||||
../../../../src/render/ShadowMap.cpp
|
||||
../../../../src/Game.cpp
|
||||
../../../../src/Game.h
|
||||
../../../../src/Character.cpp
|
||||
../../../../src/Character.h
|
||||
../../../../src/CharacterState.cpp
|
||||
../../../../src/CharacterState.h
|
||||
../../../../src/Environment.cpp
|
||||
../../../../src/Environment.h
|
||||
../../../../src/Localization.cpp
|
||||
../../../../src/Localization.h
|
||||
../../../../src/render/Renderer.cpp
|
||||
../../../../src/render/Renderer.h
|
||||
../../../../src/render/PathVisualization.cpp
|
||||
../../../../src/render/PathVisualization.h
|
||||
../../../../src/render/ShaderManager.cpp
|
||||
../../../../src/render/ShaderManager.h
|
||||
../../../../src/render/TextureManager.cpp
|
||||
../../../../src/render/TextureManager.h
|
||||
../../../../src/TextModel.cpp
|
||||
../../../../src/TextModel.h
|
||||
../../../../src/AudioPlayerAsync.cpp
|
||||
../../../../src/AudioPlayerAsync.h
|
||||
../../../../src/BoneAnimatedModelNew.cpp
|
||||
../../../../src/BoneAnimatedModelNew.h
|
||||
../../../../src/render/OpenGlExtensions.cpp
|
||||
)
|
||||
|
||||
# Подключаем заголовки
|
||||
target_include_directories(main PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../SDL/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../zlib
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../libpng
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/eigen-5.0.0
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/boost_1_90_0
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../../src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../libzip
|
||||
)
|
||||
|
||||
# ВАЖНО: Линкуемся с png_static (статика) или png_shared (динамика)
|
||||
# Так как мы установили PNG_STATIC=ON и PNG_SHARED=OFF,
|
||||
# должна создаться цель png_static
|
||||
target_link_libraries(main
|
||||
png_static # ← ЭТО ПРАВИЛЬНОЕ ИМЯ ЦЕЛИ!
|
||||
z
|
||||
SDL2
|
||||
../../../../src/render/OpenGlExtensions.h
|
||||
../../../../src/utils/Utils.cpp
|
||||
../../../../src/utils/Utils.h
|
||||
../../../../src/SparkEmitter.cpp
|
||||
../../../../src/SparkEmitter.h
|
||||
../../../../src/TeleportZone.h
|
||||
../../../../src/TeleportZone.cpp
|
||||
../../../../src/utils/TaskManager.cpp
|
||||
../../../../src/utils/TaskManager.h
|
||||
../../../../src/render/FrameBuffer.cpp
|
||||
../../../../src/render/FrameBuffer.h
|
||||
../../../../src/render/ShadowMap.cpp
|
||||
../../../../src/render/ShadowMap.h
|
||||
../../../../src/UiManager.cpp
|
||||
../../../../src/UiManager.h
|
||||
../../../../src/render/TextRenderer.h
|
||||
../../../../src/render/TextRenderer.cpp
|
||||
../../../../src/MenuManager.h
|
||||
../../../../src/MenuManager.cpp
|
||||
../../../../src/Location.h
|
||||
../../../../src/Location.cpp
|
||||
../../../../src/LocationState.h
|
||||
../../../../src/LocationState.cpp
|
||||
../../../../src/LocationGameState.h
|
||||
../../../../src/LocationGameState.cpp
|
||||
../../../../src/LocationEditor.h
|
||||
../../../../src/LocationEditor.cpp
|
||||
../../../../src/NpcCar.h
|
||||
../../../../src/NpcCar.cpp
|
||||
../../../../src/GameConstants.h
|
||||
../../../../src/GameConstants.cpp
|
||||
../../../../src/GameState.h
|
||||
../../../../src/GameState.cpp
|
||||
../../../../src/content/LocationDefinition.cpp
|
||||
../../../../src/game_server/IGameServer.h
|
||||
../../../../src/game_server/InternalGameServer.h
|
||||
../../../../src/game_server/InternalGameServer.cpp
|
||||
../../../../src/game_server/LocalGameServerHost.cpp
|
||||
../../../../src/ScriptEngine.h
|
||||
../../../../src/ScriptEngine.cpp
|
||||
../../../../src/navigation/PathFinder.h
|
||||
../../../../src/navigation/PathFinder.cpp
|
||||
../../../../src/items/GameObjectLoader.h
|
||||
../../../../src/items/GameObjectLoader.cpp
|
||||
../../../../src/items/Item.h
|
||||
../../../../src/items/Item.cpp
|
||||
../../../../src/items/Inventory.cpp
|
||||
../../../../src/items/ItemRegistry.h
|
||||
../../../../src/items/ItemRegistry.cpp
|
||||
../../../../src/Campaign.cpp
|
||||
../../../../src/items/InteractiveObject.h
|
||||
../../../../src/items/InteractiveObject.cpp
|
||||
../../../../src/items/InteractiveObjectState.cpp
|
||||
../../../../src/items/InteractiveObjectState.h
|
||||
../../../../src/dialogue/DialogueTypes.h
|
||||
../../../../src/dialogue/DialogueDatabase.h
|
||||
../../../../src/dialogue/DialogueDatabase.cpp
|
||||
../../../../src/dialogue/DialogueRuntime.h
|
||||
../../../../src/dialogue/DialogueRuntime.cpp
|
||||
../../../../src/dialogue/DialogueOverlay.h
|
||||
../../../../src/dialogue/DialogueOverlay.cpp
|
||||
../../../../src/dialogue/DialogueSystem.h
|
||||
../../../../src/dialogue/DialogueSystem.cpp
|
||||
../../../../src/dialogue/TranslationDatabase.h
|
||||
../../../../src/dialogue/TranslationDatabase.cpp
|
||||
../../../../src/quest/QuestTypes.h
|
||||
../../../../src/quest/QuestJournal.h
|
||||
../../../../src/quest/QuestJournal.cpp
|
||||
../../../../src/cutscene/CutsceneTypes.h
|
||||
../../../../src/cutscene/CutsceneDatabase.h
|
||||
../../../../src/cutscene/CutsceneDatabase.cpp
|
||||
../../../../src/cutscene/CutsceneRuntime.h
|
||||
../../../../src/cutscene/CutsceneRuntime.cpp
|
||||
../../../../src/cutscene/CutsceneOverlay.h
|
||||
../../../../src/cutscene/CutsceneOverlay.cpp
|
||||
../../../../src/render/UiQuad.h
|
||||
)
|
||||
|
||||
|
||||
find_library(OPENGLES2_LIB GLESv2)
|
||||
|
||||
|
||||
find_library(OPENGLES3_LIB GLESv3)
|
||||
|
||||
target_link_libraries(main
|
||||
${OPENGLES2_LIB} # OpenGL ES 2.0/3.0
|
||||
${OPENGLES3_LIB}
|
||||
png_static
|
||||
z
|
||||
SDL2
|
||||
SDL2_ttf
|
||||
SDL2_mixer
|
||||
log
|
||||
android
|
||||
OpenSLES
|
||||
dl
|
||||
zip
|
||||
zip
|
||||
lua_static
|
||||
#freetype
|
||||
)
|
||||
|
||||
# Подключаем заголовки
|
||||
target_include_directories(main PRIVATE
|
||||
#${CMAKE_CURRENT_SOURCE_DIR}/../SDL/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/SDL_ttf-release-2.24.0/external/freetype/include
|
||||
|
||||
#${CMAKE_CURRENT_SOURCE_DIR}/../zlib
|
||||
#${CMAKE_CURRENT_SOURCE_DIR}/../libpng
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/eigen-5.0.0
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/boost_1_90_0
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../../src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/sol2-3.3.0/include
|
||||
#${CMAKE_CURRENT_SOURCE_DIR}/../libzip
|
||||
)
|
||||
|
||||
add_dependencies(main sync_resources)
|
||||
Vendored
+6
@@ -16,6 +16,9 @@
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# SDL2 specific rules
|
||||
-keep class org.libsdl.app.** { *; }
|
||||
|
||||
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLInputConnection {
|
||||
void nativeCommitText(java.lang.String, int);
|
||||
void nativeGenerateScancodeForUnichar(char);
|
||||
@@ -96,3 +99,6 @@
|
||||
void hapticRun(int, float, int);
|
||||
void hapticStop(int);
|
||||
}
|
||||
|
||||
# Keep our main activity
|
||||
-keep class fishrungames.shadowoverbishkek.ShadowOverBishkekActivity { *; }
|
||||
@@ -8,7 +8,7 @@
|
||||
android:installLocation="auto">
|
||||
|
||||
<!-- OpenGL ES 2.0 -->
|
||||
<uses-feature android:glEsVersion="0x00020000" />
|
||||
<uses-feature android:glEsVersion="0x00030000" />
|
||||
|
||||
<!-- Touchscreen support -->
|
||||
<uses-feature
|
||||
@@ -52,7 +52,7 @@
|
||||
<!-- <uses-permission android:name="android.permission.RECORD_AUDIO" /> -->
|
||||
|
||||
<!-- Create a Java class extending SDLActivity and place it in a
|
||||
directory under app/src/main/java matching the package, e.g. app/src/main/java/com/gamemaker/game/MyGame.java
|
||||
directory under shadowoverbishkek/main/java matching the package, e.g. shadowoverbishkek/main/java/com/gamemaker/game/MyGame.java
|
||||
|
||||
then replace "SDLActivity" with the name of your class (e.g. "MyGame")
|
||||
in the XML below.
|
||||
@@ -62,14 +62,14 @@
|
||||
<application android:label="@string/app_name"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:allowBackup="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:theme="@style/Theme.App.Starting"
|
||||
android:hardwareAccelerated="true" >
|
||||
|
||||
<!-- Example of setting SDL hints from AndroidManifest.xml:
|
||||
<meta-data android:name="SDL_ENV.SDL_ACCELEROMETER_AS_JOYSTICK" android:value="0"/>
|
||||
-->
|
||||
|
||||
<activity android:name="SDLActivity"
|
||||
|
||||
<activity android:name=".ShadowOverBishkekActivity"
|
||||
android:label="@string/app_name"
|
||||
android:alwaysRetainTaskState="true"
|
||||
android:launchMode="singleInstance"
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package fishrungames.shadowoverbishkek;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.core.splashscreen.SplashScreen;
|
||||
import org.libsdl.app.SDLActivity;
|
||||
|
||||
public class ShadowOverBishkekActivity extends SDLActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
SplashScreen.installSplashScreen(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Тень над Бишкеком</string>
|
||||
</resources>
|
||||
@@ -1,3 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Game</string>
|
||||
<string name="app_name">Shadow Over Bishkek</string>
|
||||
</resources>
|
||||
@@ -4,4 +4,13 @@
|
||||
<style name="AppTheme" parent="android:Theme.NoTitleBar.Fullscreen">
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
<!-- Тема для Splash Screen -->
|
||||
<style name="Theme.App.Starting" parent="Theme.SplashScreen">
|
||||
<!-- Черный фон -->
|
||||
<item name="windowSplashScreenBackground">#000000</item>
|
||||
<!-- Ваша картинка 512x512 -->
|
||||
<item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
|
||||
<!-- Ссылка на основную тему, которая применится после загрузки -->
|
||||
<item name="postSplashScreenTheme">@style/AppTheme</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -6,7 +6,7 @@ buildscript {
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.1.1'
|
||||
classpath 'com.android.tools.build:gradle:9.3.0'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
||||
@@ -9,7 +9,18 @@
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
android.builtInKotlin=false
|
||||
android.defaults.buildfeatures.resvalues=true
|
||||
android.dependency.useConstraints=true
|
||||
android.enableAppCompileTimeRClass=false
|
||||
android.newDsl=false
|
||||
android.r8.optimizedResourceShrinking=false
|
||||
android.r8.strictFullModeForKeepRules=false
|
||||
android.sdk.defaultTargetSdkToCompileSdkIfUnset=false
|
||||
android.uniquePackageNames=false
|
||||
android.usesSdkInManifest.disallowed=false
|
||||
org.gradle.jvmargs=-Xmx4096m
|
||||
android.useAndroidX=true
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#This file is generated by updateDaemonJvm
|
||||
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
|
||||
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
|
||||
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
|
||||
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
|
||||
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73bcfb608d1fde9fb62e462f834a3299/redirect
|
||||
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/846ee0d876d26a26f37aa1ce8de73224/redirect
|
||||
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
|
||||
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
|
||||
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/9482ddec596298c84656d31d16652665/redirect
|
||||
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/39701d92e1756bb2f141eb67cd4c660e/redirect
|
||||
toolchainVersion=21
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#Sat Jan 10 10:31:05 MSK 2026
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -85,6 +85,8 @@ add_executable(ShadowOverBishkekDemo
|
||||
../src/Localization.h
|
||||
../src/render/Renderer.cpp
|
||||
../src/render/Renderer.h
|
||||
../src/render/PathVisualization.cpp
|
||||
../src/render/PathVisualization.h
|
||||
../src/render/ShaderManager.cpp
|
||||
../src/render/ShaderManager.h
|
||||
../src/render/TextureManager.cpp
|
||||
@@ -119,6 +121,8 @@ add_executable(ShadowOverBishkekDemo
|
||||
../src/Location.cpp
|
||||
../src/LocationState.h
|
||||
../src/LocationState.cpp
|
||||
../src/LocationGameState.h
|
||||
../src/LocationGameState.cpp
|
||||
../src/LocationEditor.h
|
||||
../src/LocationEditor.cpp
|
||||
../src/NpcCar.h
|
||||
@@ -127,6 +131,15 @@ add_executable(ShadowOverBishkekDemo
|
||||
../src/GameConstants.cpp
|
||||
../src/GameState.h
|
||||
../src/GameState.cpp
|
||||
../src/content/LocationDefinition.h
|
||||
../src/content/LocationDefinition.cpp
|
||||
../src/game_server/IGameServer.h
|
||||
../src/game_server/IGameServerLifecycle.h
|
||||
../src/game_server/IGameServerHost.h
|
||||
../src/game_server/InternalGameServer.h
|
||||
../src/game_server/InternalGameServer.cpp
|
||||
../src/game_server/LocalGameServerHost.h
|
||||
../src/game_server/LocalGameServerHost.cpp
|
||||
../src/ScriptEngine.h
|
||||
../src/ScriptEngine.cpp
|
||||
../src/navigation/PathFinder.h
|
||||
@@ -135,11 +148,14 @@ add_executable(ShadowOverBishkekDemo
|
||||
../src/items/GameObjectLoader.cpp
|
||||
../src/items/Item.h
|
||||
../src/items/Item.cpp
|
||||
../src/items/Inventory.cpp
|
||||
../src/items/ItemRegistry.h
|
||||
../src/items/ItemRegistry.cpp
|
||||
../src/Campaign.cpp
|
||||
../src/items/InteractiveObject.h
|
||||
../src/items/InteractiveObject.cpp
|
||||
../src/items/InteractiveObjectState.h
|
||||
../src/items/InteractiveObjectState.cpp
|
||||
../src/dialogue/DialogueTypes.h
|
||||
../src/dialogue/DialogueDatabase.h
|
||||
../src/dialogue/DialogueDatabase.cpp
|
||||
@@ -290,7 +306,7 @@ endif()
|
||||
# ===========================================
|
||||
set(RUNTIME_RESOURCE_DIRS
|
||||
"resources"
|
||||
"audio"
|
||||
"music"
|
||||
)
|
||||
|
||||
foreach(resdir IN LISTS RUNTIME_RESOURCE_DIRS)
|
||||
|
||||
+56
-15
@@ -8,13 +8,19 @@ if(NOT CMAKE_MAKE_PROGRAM AND WIN32)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
project(bishkek-witcher LANGUAGES C CXX)
|
||||
project(ShadowOverBishkekDemo LANGUAGES C CXX)
|
||||
|
||||
option(OPTIMIZE_WEB_RESOURCES "Resize PNG images for web build (requires Python3 + Pillow)" ON)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
# Максимальная оптимизация кода и LTO (Link-Time Optimization)
|
||||
add_compile_options(-O3 -flto)
|
||||
add_link_options(-O3 -flto)
|
||||
endif()
|
||||
|
||||
# --- АВТО-ЗАГРУЗКА ЗАВИСИМОСТЕЙ ---
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/FetchDependencies.cmake")
|
||||
# Теперь гарантированно есть папка ../thirdparty со всеми исходниками
|
||||
@@ -73,6 +79,8 @@ set(SOURCES
|
||||
../src/Localization.h
|
||||
../src/render/Renderer.cpp
|
||||
../src/render/Renderer.h
|
||||
../src/render/PathVisualization.cpp
|
||||
../src/render/PathVisualization.h
|
||||
../src/render/ShaderManager.cpp
|
||||
../src/render/ShaderManager.h
|
||||
../src/render/TextureManager.cpp
|
||||
@@ -107,12 +115,21 @@ set(SOURCES
|
||||
../src/Location.cpp
|
||||
../src/LocationState.h
|
||||
../src/LocationState.cpp
|
||||
../src/LocationGameState.h
|
||||
../src/LocationGameState.cpp
|
||||
../src/LocationEditor.h
|
||||
../src/LocationEditor.cpp
|
||||
../src/NpcCar.h
|
||||
../src/NpcCar.cpp
|
||||
../src/GameConstants.h
|
||||
../src/GameConstants.cpp
|
||||
../src/GameState.h
|
||||
../src/GameState.cpp
|
||||
../src/content/LocationDefinition.cpp
|
||||
../src/game_server/IGameServer.h
|
||||
../src/game_server/InternalGameServer.h
|
||||
../src/game_server/InternalGameServer.cpp
|
||||
../src/game_server/LocalGameServerHost.cpp
|
||||
../src/ScriptEngine.h
|
||||
../src/ScriptEngine.cpp
|
||||
../src/navigation/PathFinder.h
|
||||
@@ -121,10 +138,13 @@ set(SOURCES
|
||||
../src/items/GameObjectLoader.cpp
|
||||
../src/items/Item.h
|
||||
../src/items/Item.cpp
|
||||
../src/items/Inventory.cpp
|
||||
../src/items/ItemRegistry.h
|
||||
../src/items/ItemRegistry.cpp
|
||||
../src/Campaign.cpp
|
||||
../src/items/InteractiveObject.h
|
||||
../src/items/InteractiveObject.cpp
|
||||
../src/items/InteractiveObjectState.cpp
|
||||
../src/items/InteractiveObjectState.h
|
||||
../src/dialogue/DialogueTypes.h
|
||||
../src/dialogue/DialogueDatabase.h
|
||||
@@ -150,10 +170,10 @@ set(SOURCES
|
||||
../src/render/UiQuad.h
|
||||
)
|
||||
|
||||
add_executable(bishkek-witcher ${SOURCES})
|
||||
add_executable(ShadowOverBishkekDemo ${SOURCES})
|
||||
|
||||
# Настройка путей к инклудам (используем скачанные исходники)
|
||||
target_include_directories(bishkek-witcher PRIVATE
|
||||
target_include_directories(ShadowOverBishkekDemo PRIVATE
|
||||
../src
|
||||
../thirdparty/eigen-5.0.0
|
||||
../thirdparty/boost_1_90_0
|
||||
@@ -168,7 +188,7 @@ set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "" FORCE)
|
||||
|
||||
add_subdirectory("../thirdparty/libzip-1.11.4" libzip-build)
|
||||
|
||||
target_link_libraries(bishkek-witcher PRIVATE zip z lua_static websocket.js)
|
||||
target_link_libraries(ShadowOverBishkekDemo PRIVATE zip z lua_static websocket.js)
|
||||
|
||||
# Эмскриптен-флаги
|
||||
set(EMSCRIPTEN_FLAGS
|
||||
@@ -182,10 +202,9 @@ set(EMSCRIPTEN_FLAGS
|
||||
#"-pthread"
|
||||
#"-sUSE_PTHREADS=1"
|
||||
"-fexceptions"
|
||||
"-DNETWORK"
|
||||
)
|
||||
|
||||
target_compile_options(bishkek-witcher PRIVATE ${EMSCRIPTEN_FLAGS} "-O2")
|
||||
target_compile_options(ShadowOverBishkekDemo PRIVATE ${EMSCRIPTEN_FLAGS} "-O2")
|
||||
|
||||
# Only loading.png and the shaders used before resources.zip is ready are preloaded.
|
||||
# resources.zip is downloaded asynchronously at runtime and served as a separate file.
|
||||
@@ -195,6 +214,7 @@ set(EMSCRIPTEN_LINK_FLAGS
|
||||
#"-sPTHREAD_POOL_SIZE=4"
|
||||
"-sALLOW_MEMORY_GROWTH=1"
|
||||
"-sFULL_ES3=1"
|
||||
"-lidbfs.js"
|
||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/loading.png@resources/loading.png"
|
||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/loadingProgressBar.png@resources/loadingProgressBar.png"
|
||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/loadingProgressBarFrame.png@resources/loadingProgressBarFrame.png"
|
||||
@@ -202,15 +222,14 @@ set(EMSCRIPTEN_LINK_FLAGS
|
||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_uni_interior.lua@resources/start_uni_interior.lua"
|
||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_uni_exterior.lua@resources/start_uni_exterior.lua"
|
||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start_dorm.lua@resources/start_dorm.lua"
|
||||
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../audio@audio"
|
||||
)
|
||||
|
||||
# Применяем настройки линковки
|
||||
target_link_options(bishkek-witcher PRIVATE ${EMSCRIPTEN_LINK_FLAGS})
|
||||
target_link_options(ShadowOverBishkekDemo PRIVATE ${EMSCRIPTEN_LINK_FLAGS})
|
||||
|
||||
# Для совместимости со старыми версиями CMake, если target_link_options недостаточно
|
||||
string(REPLACE ";" " " EMSCRIPTEN_LINK_FLAGS_STR "${EMSCRIPTEN_LINK_FLAGS}")
|
||||
set_target_properties(bishkek-witcher PROPERTIES
|
||||
set_target_properties(ShadowOverBishkekDemo PROPERTIES
|
||||
LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS_STR}"
|
||||
SUFFIX ".html"
|
||||
)
|
||||
@@ -254,23 +273,40 @@ else()
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
# music resources
|
||||
set(MUSIC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../music")
|
||||
set(MUSIC_ZIP "${CMAKE_CURRENT_BINARY_DIR}/music.zip")
|
||||
get_filename_component(MUSIC_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.." ABSOLUTE)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${MUSIC_ZIP}"
|
||||
COMMAND ${CMAKE_COMMAND} -E tar "cf" "${MUSIC_ZIP}" --format=zip "music"
|
||||
WORKING_DIRECTORY "${MUSIC_PARENT_DIR}"
|
||||
DEPENDS "${MUSIC_PARENT_DIR}/music"
|
||||
)
|
||||
|
||||
|
||||
add_custom_target(pack_resources DEPENDS "${RESOURCES_ZIP}")
|
||||
add_dependencies(bishkek-witcher pack_resources)
|
||||
add_dependencies(ShadowOverBishkekDemo pack_resources)
|
||||
|
||||
add_custom_target(pack_music DEPENDS "${MUSIC_ZIP}")
|
||||
add_dependencies(ShadowOverBishkekDemo pack_music)
|
||||
|
||||
|
||||
# Определяем путь к директории установки (относительно папки билда)
|
||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/public")
|
||||
|
||||
# 1. Устанавливаем основной HTML файл
|
||||
install(TARGETS bishkek-witcher
|
||||
install(TARGETS ShadowOverBishkekDemo
|
||||
RUNTIME DESTINATION .
|
||||
)
|
||||
|
||||
# 2. Устанавливаем сопутствующие файлы (JS, WASM и сгенерированный архив данных)
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/bishkek-witcher.js"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/bishkek-witcher.wasm"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/bishkek-witcher.data"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/ShadowOverBishkekDemo.js"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/ShadowOverBishkekDemo.wasm"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/ShadowOverBishkekDemo.data"
|
||||
DESTINATION .
|
||||
)
|
||||
|
||||
@@ -278,10 +314,15 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/index.html"
|
||||
DESTINATION .
|
||||
)
|
||||
|
||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/favicon.ico"
|
||||
DESTINATION .
|
||||
)
|
||||
|
||||
# resources.zip is served separately and downloaded asynchronously at runtime
|
||||
install(FILES "${RESOURCES_ZIP}" DESTINATION .)
|
||||
install(FILES "${MUSIC_ZIP}" DESTINATION .)
|
||||
|
||||
add_custom_command(TARGET bishkek-witcher POST_BUILD
|
||||
add_custom_command(TARGET ShadowOverBishkekDemo POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} --install .
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||
COMMENT "Automatically deploying to public directory..."
|
||||
|
||||
@@ -37,3 +37,14 @@ Run:
|
||||
```
|
||||
emrun --no_browser --port 8080 public
|
||||
```
|
||||
|
||||
# Release build
|
||||
|
||||
|
||||
```
|
||||
mkdir build_release
|
||||
cd build_release
|
||||
emcmake cmake -G Ninja -DCMAKE_BUILD_TYPE=Release ..
|
||||
cmake --build . --config Release
|
||||
cmake --install . --prefix ../dist
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
<!doctypehtml><html lang=en-us><head><meta charset=utf-8><meta content="text/html; charset=utf-8"http-equiv=Content-Type><title>Emscripten-Generated Code</title><style>body{font-family:arial;margin:0;padding:none}.emscripten{padding-right:0;margin-left:auto;margin-right:auto;display:block}div.emscripten{text-align:center}div.emscripten_border{border:1px solid #000}canvas.emscripten{border:0 none;background-color:#000}#emscripten_logo{display:inline-block;margin:0;padding:6px;width:265px}.spinner{height:30px;width:30px;margin:0;margin-top:20px;margin-left:20px;display:inline-block;vertical-align:top;-webkit-animation:rotation .8s linear infinite;-moz-animation:rotation .8s linear infinite;-o-animation:rotation .8s linear infinite;animation:rotation .8s linear infinite;border-left:5px solid #ebebeb;border-right:5px solid #ebebeb;border-bottom:5px solid #ebebeb;border-top:5px solid #787878;border-radius:100%;background-color:#bdd72e}@-webkit-keyframes rotation{from{-webkit-transform:rotate(0)}to{-webkit-transform:rotate(360deg)}}@-moz-keyframes rotation{from{-moz-transform:rotate(0)}to{-moz-transform:rotate(360deg)}}@-o-keyframes rotation{from{-o-transform:rotate(0)}to{-o-transform:rotate(360deg)}}@keyframes rotation{from{transform:rotate(0)}to{transform:rotate(360deg)}}#status{display:inline-block;vertical-align:top;margin-top:30px;margin-left:20px;font-weight:700;color:#787878}#progress{height:20px;width:300px}#controls{display:inline-block;float:right;vertical-align:top;margin-top:30px;margin-right:20px}#output{width:100%;height:200px;margin:0 auto;margin-top:10px;border-left:0;border-right:0px;padding-left:0;padding-right:0;display:block;background-color:#000;color:#fff;font-family:'Lucida Console',Monaco,monospace;outline:0}</style></head><body>
|
||||
<script src="https://cdn.jsdelivr.net/npm/eruda"></script>
|
||||
<script>eruda.init();</script>
|
||||
|
||||
<a href=http://emscripten.org><img id=emscripten_logo src=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZ4AAABiCAMAAABXhUXrAAAC+lBMVEUAAAAwMDDh4eE5OTc4Nzn29vY5OTk3Nzf19fW72TP29vb29vbj4+M6Ozbu7u5ITDfj4+Pr6+vr6+tcZTb19fXi4uJTWjamwjTt7e3r6+vv7+9QVja21zStzDRteTZsdzdlcDW11DPv7+/19fXr6+tkbTqy0jSvzzW41zN8jDXD4DD29vaNozV/kDXx8fHi4uL29vaqxzTv7+9uejfI5TDi4uLh4eHs7OyGlje10zT29vb6+vr29vb19fW10TLy8vLz8/OnwTOMojWuxzTl5eWUqzXj4+Pw8PCguTSBlDX19fXl5eWftTXk5OTj4+P29vadtDR3hjXi4uL19fXj4+N6izZpdjWivDN7izWMoTXF4jCZszWiuzSpxDOQozSxzDGszDrp6eni4uL19fUjIyMbGxsQEBAfHx8nJyf///8XFxf29vcTExP19fQMDAy00zT9/f0CAgK31DO51TL5+fn6+/qy0jX8/Pv7/fnj4+MICAi81zG+1jD6+/bq7tvl6tbx8u3j6NTp6en09fHs8N5paWnr79z4+vPz8/Pl5eUxMTHn7Nm/2C/o7d3c5NEsLCzf5dPi4uJ8fHzi5tOvzzTy9exiYmI1NTXa4M7v7+/y9ubm69jp7OPh59bx8fH2+u/w+eg/Pz/u8ek5OTnn6t9FRUW+3TPj59uz1Ta22DXu7u7s7ufj6ddMTExcXFyeuCvx9ene3t7Q1MPCwsKis0DU2szn7cbr6+uXl5d2dnZRUVHv9ebX19e1tbWjo6OdnZ1xcXGpvyZVVVW6urqmqZzOzs7Gxsa9z4OcvCTs8eTu8t+QkJC52zXD3jDb29u+vr6GhobS0tLk77OwsLDI2I2Kiop/f3+30TCnp6eqqqrCx7iivSza3sy6va7Kysq/2Dm61CuCgoKtra3X54+yzyrU1NSZtTC10yvC21KQpifv9cuEhISYsyfp8sHL4Gypxi3Kz77X4bfd66Olt1fO2qmrrqDAzJO4x32zuaLe6rG0ym3M1ZV+lyimqppoJhxDAAAAY3RSTlMABHoRDPYIGHP+unWwIgQuuxUwVsSFRc8PHAc69t9MO2XjCvIlJPDq7mDxrKpuV+bi10Uu/fLNUETWh3jq0cBr3LyagDqymzzGmJKNZdqpnZN7ZmG2g3WykIPewJ6ncZP49X4lcShzAAApYUlEQVR42uyaS2gTURRA3zDjjE8dB01N1CSTjJqvjRgTMPETTesnFdEEqa1aP5CViIzMQBRGrUWJghGEuPG7EHlmVNCFuHHl0pLZiJCFCwVdGPGDH3ThxjsxiaKtGj/UQg8tk5eZdwv3cO+7DEXfMmfh+DVzJ7TE3EXLFkxBY/xzZs2buzy7O9sau+Fn3NL1C9AY/5TpG5Zmf59xbfMmozH+GQvbsn/I3KlojH/D5EXjsn/Mkg1ojH/BlLnZv8KimWiMv2+nLfuXWDN2AP11Zk3IfmHXruzuloAdX9cPGnEia00YVIOJAS6aQqOWyet3f5Fz+OK5Syda49zF3V8JWoZGmk4DkGgWmQhRWERjaPSy4VhTzrFz508WiwMtUSwWr139Imj2ajTCxOKFgpHiGGTiSewvFIIuFo1WZizJNrhaPDnQf/b4wZY4frZ/oHj5UNNP20iPB5QYLBgr63pYzgalJDBotLK+aefcyWL/cZCTP/Lr5POmof5i8WrzNcJ4NMKYejq4esFw8YIR5ketnqnN4rl0cuDscXAzePszZ35G7am7oAgqaKB4tVE/86ejkSUQ3W+EGtOAa/N+I8WP2ua2qHHunDvZb9oZvDF4qxWenbkxaPrpL15s+JmGfoTHBXCIFQMihyhkEgl0bt++zQWLWCcQgw+MSxThxOBqawSw4rbOzgCHEBVxASxyuQMRytzs7uyEvVQtdgjieEKGVrA09IhBjazkPGJoWwSCxCwWC+xFHjcg/v/z3JTldTuHoHYOHhw8c+vD25st8fZ9/jYU0NmBa8fqodqmoB+QCALWWCIYjSYiph9u+2ajUNBIcBOLeqJagfSxFBKjweBmDwxeBc1IwzqWiELSowkBeTbD/kSkA/Z3UohOw2bNCG6DZ9DazYamGfGwpqnWhh5wpaVDcRjgNosoEo0aUQiL1kaBPva/97MgW+cynDsHj9z+WK0+f3CnBa5XqzdfnzkC9VM8t6s+/y1Ew8MkNFXz9ziIpqrGVkiiJ05UgjGBZYAK2OBuD0dRW+GKRYpP+zQSotHaoKYRrKkkTbk2wy1b0oDnMzCYGbXvtSBU0loDHjAMAkvJztRTvwkedGrmX9PinCvpgLBWsJ10aH4r87/rmbWoWTw1O++r119VHj3a/6s8qlSe3KlWX5/JnzgO5VP3swoNDxVJYlXBRJJUVfXbEQu68Eq3O4VVkuIoC1Gxjac8friLAwwlSNhpZ2JBFTszG21YS/CMK6yqihZWVOKmt2IVt7s7VJUEqIhfBW+9vSkNQjRmNQqeUDEOOzW4iAzdB38mxLAogEk7/9/rmdHWmAuKZw/mz7yuXn/yqPDr7N8Pv5VX1Zv9g0egfK7W9Syf/gM9TB9WVEeX1eJTFWJBAUPBHQLHiQ5VlVyU6AcRPLsWFKokw6AQIb0cncCq18LxSYyTPEPbQF2vRSJBi0gUyDIdwqbKNFbwFivPWSUV9zSGATqhKljKWC02uLuJZt1EwX0cBRH9Fu6/HxhWzK/rOT9w/OBg/u3zJ5DwoXj4Fd86qtypfrgB7a3Z3a5M/VF3S0LVZHhItqmHTkLmrRzD0GGs+kXKE1dVr522YVlRSC/LJbBkZcWggldaLT2wIUOznE/FKUEIdGeEHtjstnZLCg4LnBPiujmaFeIqac7VvKQofjfPMV3gpYNGdigxqM4AwaAV/e/Mq4/Vh+Hkyd++VX1VGbqHPX3W5MXT73rfk+dvBwfzxweO1F2fnoeGh3Yq2GbnWHqrIhOLHdJnE2iKYmy64rewTBIrDlF06Fu8CuliRbMHURkiK2GneUCthEc9DigZjmZomncqitfmJzqW3FzMoWAzEhIkhWyk63oEhwwiQFY3kUEPRSdVxStAAY6G4kHLZmdrHCr2H8zffgfFM7SexzubvPn+ZKpcv/nitqmn/vLuwo9Ga86rlFfyDLQdRXFYrQ5ZScIKMWFVgVMGtRNFD3QRvDEMEug+3WHhqLQuy2VC/LZuAXIawzLpolmKZSN+RVYIwb52C88EsFyuvStwYQW7mcZcDYuaq17Qswk+QBUpYq14wORQTJ+zYuG8BVNnoP+A8U09Z82x7XplGD3Pdu75zM5nD7+/XXnw4B50t/6GnmM/mg1cei27iPPJstMOevTaQRHxyzgFnjaV5VzahsPWFJwkLp+e4ml2K+jZ0tVtEXga0h4qy+VMLbcuhyz72ns3woFD175uNytimy77LQ09a3XZay4oiKGHYFegLMvplD5c8SxY1DYuazJ//bxZaKSZOK6uZwD0nLl/vaIN3duO7qzbOfDy0fB68g0969DwBHS53M1QcM1BFdkluZQEPZDdXLmLY83rKaej3MX3lfRUOlfeyLFUn57TMxz0M4alkCnQ4W7o0W1C/XszQDsUj8cpl5yNmZlKl0APBfYlOSdboYl6fHLOB08OWTwr5kI+mrSN+P+3fKUn/1nPUEBv27PXZM/Ox4+076npyX+lZxIaFshuTl9ppyPxklzeSHNJPeezIwTLks/KUSjmyOVykH9ukw4fdJsd0pgp5+SwRRDE2guE9nLJZ2fM3NPOklzqFQR7qJM2dZfCohCIl2AX35ire2DV4aE8STlXgmmbotgeiAvKOHb4XtJk8WTUEiOi55H2Yue+GtDahtKjPLgO1fOLejogPSUpIUHuU3CSh8qQt+7uOCy7eUifxwtWzEwGTD3l3tpp4i/lct64pJMOio7ZSrkdIdEDodi0GSse9+t+gYqYXr2SXvLBdvETsebzm0QQxXEI7K6i69ouArqgSAUOYgWNv6g/KrGpVeNvGw0aTTwIIUaCLuiBSxMl4oGYEBs9SIzR7JpwMB70oMZo4kE5mWg9WZNq4EIP/Qt8M7OWtizbEOz67YEZ5s3s9H14M28GlKyMBuO0HDq3A70Mo7GMZ1BxQC14+i7O1eVw+3z0x1MrJTGdTK4GdDrEE5WLxbSMfOSCjzBtCgCfSkWSnUOciUaJHWoaYoy2Crjejy5njPQGpyxJklxxRuhDTyVUfHrUAA3c3gqqVWS/jTYPVBBYKRJFLDnifeaClN7vr0jpIqykHEYiSMW0Uy149sDsm/gcNLQr/fFMxLNI15OwtHWKxxySJPvwfr/PNcAzyPdsxOWUnaEBNwu7DLSfdYGACrfb5VobYcgqxgfsoVB0yM2aDtmxQhvMiBt3KhoK2QOnBMZMswGf5LMPC3bov4PD7oc10+U6xu93AsCAgMc3cH4SPC2v7hOZZFJMKOWHx+f/tnnVstmCNxYKz1U11TMYT7K+uAq1n03tY23g8a5NS1GO43kbi+iAixkBbo+hRrxHe20gWObMHLxyxI20meFsAseg046XE0AcWEBns4kVbAL0RbsKw7t5gWUF6Cco0WHiYAyG5YfdPMdAD5xPpH1uleBRfqx0Tbz94e3bDyMZBdCWdQZtOSzWJoX1xFPLkeApTV4dR1rcCZ7VzqIUwYdKE3YX8IEyqeGq0Qxl8DYpgBsVI1yDd2ncFSwa76MGVCZFGlk2RsMygcAGX1q0CB4yd3Hk65NRUPmNSMLn/sF5L5WblLBu6/rHeO7c+tQCT3Xieg4p++BLHWlqvBM87grggV0GPG1QZMSatvhbU39XsZ7du1FsbiXCjzu0wbsGUrm02s4TJrHz8mYhj/DkH3/MkOv3jfMcUPtU8Ly8260bnp/1TI7wyYDipclqJ3hLine truncated
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
+1
-1
@@ -39,7 +39,7 @@
|
||||
|
||||
function loadGameScript() {
|
||||
var s = document.createElement('script');
|
||||
s.src = 'bishkek-witcher.js';
|
||||
s.src = 'ShadowOverBishkekDemo.js';
|
||||
s.async = true;
|
||||
document.body.appendChild(s);
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
<!doctypehtml><html lang=en-us><head><meta charset=utf-8><meta content="text/html; charset=utf-8"http-equiv=Content-Type><title>Emscripten-Generated Code</title><style>body{font-family:arial;margin:0;padding:none}.emscripten{padding-right:0;margin-left:auto;margin-right:auto;display:block}div.emscripten{text-align:center}div.emscripten_border{border:1px solid #000}canvas.emscripten{border:0 none;background-color:#000}#emscripten_logo{display:inline-block;margin:0;padding:6px;width:265px}.spinner{height:30px;width:30px;margin:0;margin-top:20px;margin-left:20px;display:inline-block;vertical-align:top;-webkit-animation:rotation .8s linear infinite;-moz-animation:rotation .8s linear infinite;-o-animation:rotation .8s linear infinite;animation:rotation .8s linear infinite;border-left:5px solid #ebebeb;border-right:5px solid #ebebeb;border-bottom:5px solid #ebebeb;border-top:5px solid #787878;border-radius:100%;background-color:#bdd72e}@-webkit-keyframes rotation{from{-webkit-transform:rotate(0)}to{-webkit-transform:rotate(360deg)}}@-moz-keyframes rotation{from{-moz-transform:rotate(0)}to{-moz-transform:rotate(360deg)}}@-o-keyframes rotation{from{-o-transform:rotate(0)}to{-o-transform:rotate(360deg)}}@keyframes rotation{from{transform:rotate(0)}to{transform:rotate(360deg)}}#status{display:inline-block;vertical-align:top;margin-top:30px;margin-left:20px;font-weight:700;color:#787878}#progress{height:20px;width:300px}#controls{display:inline-block;float:right;vertical-align:top;margin-top:30px;margin-right:20px}#output{width:100%;height:200px;margin:0 auto;margin-top:10px;border-left:0;border-right:0px;padding-left:0;padding-right:0;display:block;background-color:#000;color:#fff;font-family:'Lucida Console',Monaco,monospace;outline:0}</style></head><body><script src="https://cdn.jsdelivr.net/npm/eruda"></script>
|
||||
<script>eruda.init();</script><a href=http://emscripten.org><img id=emscripten_logo src=""></a><div class=spinner id=spinner></div><div class=emscripten id=status>Downloading...</div><span id=controls><span><input type=checkbox id=resize>Resize canvas</span> <span><input type=checkbox id=pointerLock checked>Lock/hide mouse pointer </span><span><input type=button onclick='Module.requestFullscreen(document.getElementById("pointerLock").checked,document.getElementById("resize").checked)'value=Fullscreen></span></span><div class=emscripten><progress hidden id=progress max=100 value=0></progress></div><div class=emscripten_border><canvas class=emscripten id=canvas oncontextmenu=event.preventDefault() tabindex=-1></canvas></div><textarea id=output rows=8></textarea><script>var statusElement=document.getElementById("status"),progressElement=document.getElementById("progress"),spinnerElement=document.getElementById("spinner"),canvasElement=document.getElementById("canvas"),outputElement=document.getElementById("output");outputElement&&(outputElement.value=""),canvasElement.addEventListener("webglcontextlost",(e=>{alert("WebGL context lost. You will need to reload the page."),e.preventDefault()}),!1);var Module={print(...e){if(console.log(...e),outputElement){var t=e.join(" ");outputElement.value+=t+"\n",outputElement.scrollTop=outputElement.scrollHeight}},canvas:canvasElement,setStatus(e){if(Module.setStatus.last||(Module.setStatus.last={time:Date.now(),text:""}),e!==Module.setStatus.last.text){var t=e.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/),n=Date.now();t&&n-Module.setStatus.last.time<30||(Module.setStatus.last.time=n,Module.setStatus.last.text=e,t?(e=t[1],progressElement.value=100*parseInt(t[2]),progressElement.max=100*parseInt(t[4]),progressElement.hidden=!1,spinnerElement.hidden=!1):(progressElement.value=null,progressElement.max=null,progressElement.hidden=!0,e||(spinnerElement.style.display="none")),statusElement.innerHTML=e)}},totalDependencies:0,monitorRunDependencies(e){this.totalDependencies=Math.max(this.totalDependencies,e),Module.setStatus(e?"Preparing... ("+(this.totalDependencies-e)+"/"+this.totalDependencies+")":"All downloads complete.")}};Module.setStatus("Downloading..."),window.onerror=e=>{Module.setStatus("Exception thrown, see JavaScript console"),spinnerElement.style.display="none",Module.setStatus=e=>{e&&console.error("[post-exception status] "+e)}}</script><script async src="space-game001.js" crossorigin="anonymous"></script></body></html>
|
||||
@@ -1,200 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||
<title>Sky Trek Tales</title>
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0; padding: 0; width: 100%; height: 100%;
|
||||
overflow: hidden; background-color: #000;
|
||||
position: fixed;
|
||||
}
|
||||
#canvas {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100vw; height: 100vh;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#fs-button {
|
||||
position: absolute;
|
||||
top: 10px; right: 10px;
|
||||
padding: 10px;
|
||||
z-index: 10;
|
||||
background: rgba(255,255,255,0.3);
|
||||
color: white; border: 1px solid white;
|
||||
cursor: pointer;
|
||||
font-family: sans-serif;
|
||||
border-radius: 5px;
|
||||
}
|
||||
#status { color: white; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
|
||||
|
||||
/* Nick modal */
|
||||
#nickOverlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(0,0,0,0.85);
|
||||
z-index: 9999;
|
||||
}
|
||||
#nickBox {
|
||||
background: #111;
|
||||
border: 1px solid #444;
|
||||
padding: 24px;
|
||||
width: 320px;
|
||||
box-shadow: 0 8px 24px rgba(0,0,0,0.6);
|
||||
text-align: center;
|
||||
}
|
||||
#nickBox h2 { margin: 0 0 12px 0; font-size: 18px; color: #eee; }
|
||||
#nickBox input[type="text"] {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 12px;
|
||||
border: 1px solid #333;
|
||||
background: #000;
|
||||
color: #fff;
|
||||
}
|
||||
#nickBox button {
|
||||
padding: 10px 16px;
|
||||
font-size: 16px;
|
||||
background: #2a9fd6;
|
||||
border: none;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<button id="fs-button">Fullscreen</button>
|
||||
<div id="status">Downloading...</div>
|
||||
<canvas id="canvas" oncontextmenu="event.preventDefault()" tabindex="-1"></canvas>
|
||||
<div id="nickOverlay" style="display:none;">
|
||||
<div id="nickBox">
|
||||
<h2>Enter your nickname</h2>
|
||||
<input id="nickInput" type="text" maxlength="32" placeholder="Player" />
|
||||
<div>
|
||||
<button id="nickSubmit">Start</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Utility: подготовить глобальный Module до загрузки Emscripten-скрипта
|
||||
function prepareModuleEnvironment() {
|
||||
window.Module = window.Module || {};
|
||||
var canvasEl = document.getElementById('canvas');
|
||||
// Устанавливаем canvas для Emscripten, чтобы createContext не падал
|
||||
window.Module.canvas = canvasEl;
|
||||
// Подготовим заглушку setStatus, если ещё нет
|
||||
window.Module.setStatus = window.Module.setStatus || function (text) {
|
||||
var statusElement = document.getElementById("status");
|
||||
statusElement.innerHTML = text;
|
||||
statusElement.style.display = text ? 'block' : 'none';
|
||||
};
|
||||
}
|
||||
|
||||
// Show overlay only if no nickname saved.
|
||||
function loadGameScript() {
|
||||
var s = document.createElement('script');
|
||||
s.src = 'space-game001.js';
|
||||
s.async = true;
|
||||
document.body.appendChild(s);
|
||||
}
|
||||
|
||||
function showNickOverlay() {
|
||||
var overlay = document.getElementById('nickOverlay');
|
||||
overlay.style.display = 'flex';
|
||||
var input = document.getElementById('nickInput');
|
||||
input.focus();
|
||||
}
|
||||
|
||||
function hideNickOverlay() {
|
||||
var overlay = document.getElementById('nickOverlay');
|
||||
overlay.style.display = 'none';
|
||||
}
|
||||
|
||||
function saveNickAndStart(nick) {
|
||||
try {
|
||||
if (!nick || nick.trim() === '') nick = 'Player';
|
||||
localStorage.setItem('spacegame_nick', nick);
|
||||
} catch (e) {
|
||||
console.warn('localStorage not available', e);
|
||||
}
|
||||
hideNickOverlay();
|
||||
// перед загрузкой скрипта гарантируем, что Module.canvas задан
|
||||
prepareModuleEnvironment();
|
||||
loadGameScript();
|
||||
}
|
||||
|
||||
document.getElementById('fs-button').addEventListener('click', function() {
|
||||
if (!document.fullscreenElement) {
|
||||
document.documentElement.requestFullscreen().catch(function(e) {
|
||||
console.error('Fullscreen error: ' + e.message);
|
||||
});
|
||||
} else {
|
||||
document.exitFullscreen();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Готовим Module сразу — даже если откроется модалка, поле canvas будет доступно для скрипта (если он загружается позже)
|
||||
prepareModuleEnvironment();
|
||||
|
||||
var stored = null;
|
||||
try {
|
||||
stored = localStorage.getItem('spacegame_nick');
|
||||
} catch (e) {
|
||||
console.warn('localStorage not available', e);
|
||||
}
|
||||
|
||||
if (stored && stored.trim() !== '') {
|
||||
// Nick is present — start immediately
|
||||
loadGameScript();
|
||||
} else {
|
||||
// Show modal to request nickname before loading WASM
|
||||
showNickOverlay();
|
||||
var submit = document.getElementById('nickSubmit');
|
||||
var input = document.getElementById('nickInput');
|
||||
|
||||
submit.addEventListener('click', function() {
|
||||
saveNickAndStart(input.value);
|
||||
});
|
||||
|
||||
input.addEventListener('input', function() {
|
||||
// Strip any character that is not a-z, A-Z, 0-9 or space
|
||||
var pos = this.selectionStart;
|
||||
var cleaned = this.value.replace(/[^a-zA-Z0-9 ]/g, '');
|
||||
if (cleaned !== this.value) {
|
||||
this.value = cleaned;
|
||||
this.setSelectionRange(pos - 1, pos - 1);
|
||||
}
|
||||
});
|
||||
|
||||
input.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
saveNickAndStart(input.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("orientationchange", function() {
|
||||
// Chrome на Android обновляет innerWidth/Height не мгновенно.
|
||||
// Ждем завершения анимации поворота.
|
||||
setTimeout(() => {
|
||||
// В Emscripten это вызовет ваш onWindowResized в C++
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
}, 200);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
+123
-55
@@ -27,6 +27,8 @@ add_executable(ShadowOverBishkekDemo WIN32
|
||||
../src/Localization.h
|
||||
../src/render/Renderer.cpp
|
||||
../src/render/Renderer.h
|
||||
../src/render/PathVisualization.cpp
|
||||
../src/render/PathVisualization.h
|
||||
../src/render/ShaderManager.cpp
|
||||
../src/render/ShaderManager.h
|
||||
../src/render/TextureManager.cpp
|
||||
@@ -61,6 +63,8 @@ add_executable(ShadowOverBishkekDemo WIN32
|
||||
../src/Location.cpp
|
||||
../src/LocationState.h
|
||||
../src/LocationState.cpp
|
||||
../src/LocationGameState.h
|
||||
../src/LocationGameState.cpp
|
||||
../src/LocationEditor.h
|
||||
../src/LocationEditor.cpp
|
||||
../src/NpcCar.h
|
||||
@@ -69,6 +73,17 @@ add_executable(ShadowOverBishkekDemo WIN32
|
||||
../src/GameConstants.cpp
|
||||
../src/GameState.h
|
||||
../src/GameState.cpp
|
||||
../src/content/LocationDefinition.h
|
||||
../src/content/LocationDefinition.cpp
|
||||
../src/game_server/IGameServer.h
|
||||
../src/game_server/IGameServerLifecycle.h
|
||||
../src/game_server/IGameServerHost.h
|
||||
../src/game_server/GameServerRouter.h
|
||||
../src/game_server/GameServerHostRouter.h
|
||||
../src/game_server/InternalGameServer.h
|
||||
../src/game_server/InternalGameServer.cpp
|
||||
../src/game_server/LocalGameServerHost.h
|
||||
../src/game_server/LocalGameServerHost.cpp
|
||||
../src/ScriptEngine.h
|
||||
../src/ScriptEngine.cpp
|
||||
../src/navigation/PathFinder.h
|
||||
@@ -77,11 +92,14 @@ add_executable(ShadowOverBishkekDemo WIN32
|
||||
../src/items/GameObjectLoader.cpp
|
||||
../src/items/Item.h
|
||||
../src/items/Item.cpp
|
||||
../src/items/Inventory.cpp
|
||||
../src/items/ItemRegistry.h
|
||||
../src/items/ItemRegistry.cpp
|
||||
../src/Campaign.cpp
|
||||
../src/items/InteractiveObject.h
|
||||
../src/items/InteractiveObject.cpp
|
||||
../src/items/InteractiveObjectState.h
|
||||
../src/items/InteractiveObjectState.cpp
|
||||
../src/dialogue/DialogueTypes.h
|
||||
../src/dialogue/DialogueDatabase.h
|
||||
../src/dialogue/DialogueDatabase.cpp
|
||||
@@ -104,6 +122,7 @@ add_executable(ShadowOverBishkekDemo WIN32
|
||||
../src/cutscene/CutsceneOverlay.h
|
||||
../src/cutscene/CutsceneOverlay.cpp
|
||||
../src/render/UiQuad.h
|
||||
app.rc
|
||||
)
|
||||
|
||||
# Установка проекта по умолчанию для Visual Studio
|
||||
@@ -118,15 +137,12 @@ set_target_properties(ShadowOverBishkekDemo PROPERTIES
|
||||
OUTPUT_NAME "ShadowOverBishkekDemo"
|
||||
)
|
||||
|
||||
# Определения препроцессора:
|
||||
# PNG_ENABLED – включает код PNG в TextureManager
|
||||
# SDL_MAIN_HANDLED – отключает переопределение main -> SDL_main
|
||||
# Определения препроцессора
|
||||
target_compile_definitions(ShadowOverBishkekDemo PRIVATE
|
||||
WIN32_LEAN_AND_MEAN
|
||||
_WIN32_WINNT=0x0A00
|
||||
PNG_ENABLED
|
||||
# SDL_MAIN_HANDLED
|
||||
# DEBUG_LIGHT
|
||||
# SHOW_PATH
|
||||
NETWORK
|
||||
)
|
||||
|
||||
# Линкуем с SDL2main, если он вообще установлен
|
||||
@@ -148,7 +164,16 @@ target_link_libraries(ShadowOverBishkekDemo PRIVATE
|
||||
|
||||
# Линкуем OpenGL (Windows)
|
||||
if(WIN32)
|
||||
target_link_libraries(ShadowOverBishkekDemo PRIVATE opengl32)
|
||||
target_sources(ShadowOverBishkekDemo PRIVATE
|
||||
../src/game_server/NetworkProtocol.h
|
||||
../src/game_server/NetworkProtocol.cpp
|
||||
../src/game_server/WebsocketGameClient.h
|
||||
../src/game_server/WebsocketGameClient.cpp
|
||||
../src/game_server/RemoteGameServerHost.h
|
||||
../src/game_server/RemoteGameServerHost.cpp
|
||||
)
|
||||
target_link_libraries(
|
||||
ShadowOverBishkekDemo PRIVATE opengl32 ws2_32 mswsock)
|
||||
endif()
|
||||
|
||||
# ===========================================
|
||||
@@ -157,18 +182,15 @@ endif()
|
||||
if(STEAMSDK)
|
||||
message(STATUS "Steamworks SDK integration is ENABLED.")
|
||||
|
||||
# Макрос STEAMSDK для условной компиляции в C++ коде (#ifdef STEAMSDK)
|
||||
target_compile_definitions(ShadowOverBishkekDemo PRIVATE STEAMSDK)
|
||||
|
||||
set(STEAM_SDK_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/steamworks_sdk_164/sdk")
|
||||
|
||||
# Подключение заголовочных файлов Steamworks
|
||||
target_include_directories(ShadowOverBishkekDemo PRIVATE
|
||||
"${STEAM_SDK_DIR}/public"
|
||||
"${STEAM_SDK_DIR}/public/steam"
|
||||
)
|
||||
|
||||
# Определение разрядности сборки (x86 vs x64) для выбора версий lib и dll
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(STEAM_LIB_DIR "${STEAM_SDK_DIR}/redistributable_bin/win64")
|
||||
set(STEAM_LIB_NAME "steam_api64")
|
||||
@@ -179,7 +201,6 @@ if(STEAMSDK)
|
||||
set(STEAM_DLL_NAME "steam_api.dll")
|
||||
endif()
|
||||
|
||||
# Поиск библиотеки линковки (.lib)
|
||||
find_library(STEAM_LIBRARY
|
||||
NAMES ${STEAM_LIB_NAME}
|
||||
PATHS ${STEAM_LIB_DIR}
|
||||
@@ -193,22 +214,18 @@ if(STEAMSDK)
|
||||
message(FATAL_ERROR "Steam API library (${STEAM_LIB_NAME}) NOT found in ${STEAM_LIB_DIR}!")
|
||||
endif()
|
||||
|
||||
# Генерация временного файла steam_appid.txt с ID демо-версии (4945840)
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/steam_appid.txt" "4945840")
|
||||
else()
|
||||
message(STATUS "Steamworks SDK integration is DISABLED.")
|
||||
endif()
|
||||
|
||||
# ===========================================
|
||||
# Копирование SDL2d.dll и zlibd.dll рядом с exe
|
||||
# Копирование DLL и ресурсов для локального запуска в Visual Studio
|
||||
# ===========================================
|
||||
if (WIN32)
|
||||
|
||||
# SDL2: в Debug - SDL2d.dll, в Release - SDL2.dll
|
||||
set(SDL2_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2_INSTALL_DIR}/bin/SDL2d.dll,${SDL2_INSTALL_DIR}/bin/SDL2.dll>")
|
||||
set(SDL2_DLL_DST "$<IF:$<CONFIG:Debug>,$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/SDL2d.dll,$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/SDL2.dll>")
|
||||
|
||||
|
||||
set(LIBZIP_DLL_SRC "$<IF:$<CONFIG:Debug>,${LIBZIP_BASE_DIR}-Debug/bin/zip.dll,${LIBZIP_BASE_DIR}-Release/bin/zip.dll>")
|
||||
|
||||
set(ZLIB_DLL_SRC "$<IF:$<CONFIG:Debug>,${ZLIB_INSTALL_DIR}/bin/zd.dll,${ZLIB_INSTALL_DIR}/bin/z.dll>")
|
||||
@@ -216,47 +233,26 @@ if (WIN32)
|
||||
|
||||
set(SDL2TTF_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2TTF_BASE_DIR}-Debug/bin/SDL2_ttfd.dll,${SDL2TTF_BASE_DIR}-Release/bin/SDL2_ttf.dll>")
|
||||
|
||||
set(SDL2MIXER_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2MIXER_BASE_DIR}-Debug/bin/SDL2_mixerd.dll,${SDL2MIXER_BASE_DIR}-Release/bin/SDL2_mixer.dll>")
|
||||
|
||||
add_custom_command(TARGET ShadowOverBishkekDemo POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Copying DLLs to output folder..."
|
||||
|
||||
# Копируем SDL2
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${SDL2_DLL_SRC}"
|
||||
"${SDL2_DLL_DST}"
|
||||
|
||||
# Копируем LIBZIP (целевое имя всегда zip.dll)
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${LIBZIP_DLL_SRC}"
|
||||
"$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/zip.dll"
|
||||
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${ZLIB_DLL_SRC}"
|
||||
"${ZLIB_DLL_DST}"
|
||||
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${SDL2TTF_DLL_SRC}"
|
||||
"$<TARGET_FILE_DIR:ShadowOverBishkekDemo>"
|
||||
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SDL2_DLL_SRC}" "${SDL2_DLL_DST}"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${LIBZIP_DLL_SRC}" "$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/zip.dll"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${ZLIB_DLL_SRC}" "${ZLIB_DLL_DST}"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SDL2TTF_DLL_SRC}" "$<TARGET_FILE_DIR:ShadowOverBishkekDemo>"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/SDL_mixer-release-2.8.0/install-$<CONFIG>/bin/SDL2_mixer$<$<CONFIG:Debug>:d>.dll"
|
||||
"$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/SDL2_mixer$<$<CONFIG:Debug>:d>.dll"
|
||||
)
|
||||
|
||||
# Если включен Steam, добавляем шаги копирования DLL и appid в этот же POST_BUILD
|
||||
if(STEAMSDK)
|
||||
add_custom_command(TARGET ShadowOverBishkekDemo POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Copying Steam SDK components..."
|
||||
# Копирование dll к исполняемому файлу
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${STEAM_LIB_DIR}/${STEAM_DLL_NAME}"
|
||||
"$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/${STEAM_DLL_NAME}"
|
||||
# Копирование steam_appid.txt к исполняемому файлу
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/steam_appid.txt"
|
||||
"$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/steam_appid.txt"
|
||||
# Дублируем steam_appid.txt в корень сборки (полезно при отладке прямо из MSVC)
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/steam_appid.txt"
|
||||
"${CMAKE_BINARY_DIR}/steam_appid.txt"
|
||||
@@ -264,27 +260,99 @@ if (WIN32)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ===========================================
|
||||
# Копирование ресурсов после сборки
|
||||
# ===========================================
|
||||
|
||||
# Какие папки с ресурсами нужно копировать
|
||||
set(RUNTIME_RESOURCE_DIRS
|
||||
"resources"
|
||||
"audio"
|
||||
)
|
||||
|
||||
# Копируем ресурсы и шейдеры в папку exe и в корень build/
|
||||
# Копирование ресурсов локально
|
||||
set(RUNTIME_RESOURCE_DIRS "resources" "music")
|
||||
foreach(resdir IN LISTS RUNTIME_RESOURCE_DIRS)
|
||||
add_custom_command(TARGET ShadowOverBishkekDemo POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Copying ${resdir} to runtime folders..."
|
||||
# 1) туда, где лежит exe (build/Debug, build/Release и т.п.)
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/../${resdir}"
|
||||
"$<TARGET_FILE_DIR:ShadowOverBishkekDemo>/${resdir}"
|
||||
# 2) в корень build, если захочешь запускать из этой папки
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/../${resdir}"
|
||||
"${CMAKE_BINARY_DIR}/${resdir}"
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# ===========================================
|
||||
# ПРАВИЛА ИНСТАЛЛЯЦИИ (Для CPack и создания пакетов)
|
||||
# ===========================================
|
||||
|
||||
# 1. Основной исполняемый файл
|
||||
install(TARGETS ShadowOverBishkekDemo DESTINATION .)
|
||||
|
||||
# 2. Необходимые DLL
|
||||
if(WIN32)
|
||||
install(FILES
|
||||
"${SDL2_INSTALL_DIR}/bin/SDL2.dll"
|
||||
"${LIBZIP_BASE_DIR}-Release/bin/zip.dll"
|
||||
"${ZLIB_INSTALL_DIR}/bin/z.dll"
|
||||
"${SDL2TTF_BASE_DIR}-Release/bin/SDL2_ttf.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/SDL_mixer-release-2.8.0/install-Release/bin/SDL2_mixer.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/concrt140.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/msvcp140.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/msvcp140_1.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/msvcp140_2.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/msvcp140_atomic_wait.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/msvcp140_clr0400.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/msvcp140_codecvt_ids.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/msvcp140d.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/OpenAL32.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/vcamp140.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/vccorlib140.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/vcomp140.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/vcruntime140.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/vcruntime140_1.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/vcruntime140_1_clr0400.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/vcruntime140_threads.dll"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dist_dlls/wrap_oal.dll"
|
||||
DESTINATION .
|
||||
)
|
||||
|
||||
if(STEAMSDK)
|
||||
install(FILES
|
||||
"${STEAM_LIB_DIR}/${STEAM_DLL_NAME}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/steam_appid.txt"
|
||||
DESTINATION .
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# 3. Директории с ресурсами
|
||||
foreach(resdir IN LISTS RUNTIME_RESOURCE_DIRS)
|
||||
install(DIRECTORY "${CMAKE_SOURCE_DIR}/../${resdir}" DESTINATION .)
|
||||
endforeach()
|
||||
|
||||
# ===========================================
|
||||
# НАСТРОЙКА CPACK (Создание ZIP Portable и NSIS Installer)
|
||||
# ===========================================
|
||||
set(CPACK_PACKAGE_NAME "ShadowOverBishkekDemo")
|
||||
set(CPACK_PACKAGE_VENDOR "Fish Run Games")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Shadow Over Bishkek Demo Version")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "1")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "0")
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "5")
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Fish Run Games/Shadow Over Bishkek Demo")
|
||||
|
||||
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt")
|
||||
|
||||
# Настройки NSIS инсталлятора
|
||||
set(CPACK_NSIS_DISPLAY_NAME "Shadow Over Bishkek Demo")
|
||||
set(CPACK_NSIS_PACKAGE_NAME "Shadow Over Bishkek Demo")
|
||||
set(CPACK_NSIS_HELP_LINK "https://fishrungames.com/contact.html")
|
||||
set(CPACK_NSIS_URL_INFO_ABOUT "https://shadowoverbishkek.com/")
|
||||
set(CPACK_NSIS_MODIFY_PATH OFF)
|
||||
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
|
||||
|
||||
# Иконки и ярлыки в меню Пуск и на Рабочем столе
|
||||
set(CPACK_NSIS_MUI_ICON "${CMAKE_CURRENT_SOURCE_DIR}/icon.ico")
|
||||
set(CPACK_NSIS_MUI_UNIICON "${CMAKE_CURRENT_SOURCE_DIR}/icon.ico")
|
||||
set(CPACK_NSIS_CREATE_ICONS_EXTRA
|
||||
"CreateShortCut '$DESKTOP\\\\Shadow Over Bishkek Demo.lnk' '$INSTDIR\\\\ShadowOverBishkekDemo.exe'"
|
||||
)
|
||||
|
||||
# Форматы генераторов: ZIP (Portable) и NSIS (Установщик)
|
||||
set(CPACK_GENERATOR "ZIP;NSIS")
|
||||
|
||||
include(CPack)
|
||||
@@ -0,0 +1,21 @@
|
||||
END USER LICENSE AGREEMENT (EULA)
|
||||
|
||||
Game: Shadow Over Bishkek (Demo Version)
|
||||
Developer: Fish Run Games
|
||||
|
||||
1. GRANT OF LICENSE
|
||||
Fish Run Games grants you a non-exclusive, non-transferable, limited license to download, install, and play the Shadow Over Bishkek Demo for personal, non-commercial entertainment purposes.
|
||||
|
||||
2. OWNERSHIP & INTELLECTUAL PROPERTY
|
||||
The game, including all code, graphics, audio, characters, storyline, and assets, is the intellectual property of Fish Run Games and is protected by copyright and other intellectual property laws. You may not reverse engineer, decompile, modify, or redistribute the software without express written permission.
|
||||
|
||||
3. DISCLAIMER OF WARRANTY
|
||||
THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
4. USER DATA AND SAVES
|
||||
Save files and local configuration options are stored locally on your device. Fish Run Games is not responsible for any loss of save data resulting from software updates, system crashes, or uninstallation.
|
||||
|
||||
5. TERMINATION
|
||||
This license is effective until terminated. Your rights under this license will terminate automatically without notice from Fish Run Games if you fail to comply with any term(s) of this agreement.
|
||||
|
||||
Copyright (c) 2026 Fish Run Games. All rights reserved.
|
||||
@@ -0,0 +1 @@
|
||||
IDI_ICON1 ICON "icon.ico"
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 361 KiB |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"campaigns": [
|
||||
{
|
||||
"id": "main",
|
||||
"title": { "ru": "Основная игра", "en": "Main Game" },
|
||||
"locations": [
|
||||
"resources/config/locations/location_dorm.json",
|
||||
"resources/config/locations/uni_exterior.json",
|
||||
"resources/config/locations/uni_interior.json"
|
||||
],
|
||||
"startLocation": "location_dorm",
|
||||
"startMusic": "music/obshaga.ogg",
|
||||
"startState": "resources/config/start_state.json",
|
||||
"quests": "resources/config/quests.json",
|
||||
"tutorial": true,
|
||||
"loadingScreen": "resources/w/ui/screen_loading.json"
|
||||
},
|
||||
{
|
||||
"id": "battle_zone",
|
||||
"title": { "ru": "Зона боя (одиночная)", "en": "Battle Zone (Single Player)" },
|
||||
"locations": [
|
||||
"resources/config/locations/battle_zone_uni_exterior.json"
|
||||
],
|
||||
"startLocation": "uni_exterior",
|
||||
"startMusic": "music/bishkek univer day.ogg",
|
||||
"startState": "resources/config/start_state_battle_zone.json",
|
||||
"quests": "resources/config/quests_battle_zone.json",
|
||||
"tutorial": false,
|
||||
"loadingScreen": "resources/w/ui/screen_loading.json"
|
||||
},
|
||||
{
|
||||
"id": "battle_zone_multiplayer",
|
||||
"title": { "ru": "Зона боя (сетевая)", "en": "Battle Zone (Multiplayer)" },
|
||||
"locations": [
|
||||
"resources/config/locations/battle_zone_uni_exterior.json"
|
||||
],
|
||||
"startLocation": "uni_exterior",
|
||||
"startMusic": "music/bishkek univer day.ogg",
|
||||
"startState": "resources/config/start_state_battle_zone.json",
|
||||
"quests": "resources/config/quests_battle_zone.json",
|
||||
"tutorial": false,
|
||||
"networkPlayerSlots": ["player", "player2"],
|
||||
"networkCompatibility": "battle-zone-lockstep-v2",
|
||||
"loadingScreen": "resources/w/ui/screen_loading.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"objects": [
|
||||
{
|
||||
"id": "WashingMachine002",
|
||||
"name": "WashingMachine002",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -27,6 +28,7 @@
|
||||
"activateFunction": "on_washing_machine1_click"
|
||||
},
|
||||
{
|
||||
"id": "Dryer002",
|
||||
"name": "Dryer002",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -53,6 +55,7 @@
|
||||
"activateFunction": "on_dryer1_click"
|
||||
},
|
||||
{
|
||||
"id": "Toilet001",
|
||||
"name": "Toilet001",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -79,6 +82,7 @@
|
||||
"activateFunction": "on_toilet_click"
|
||||
},
|
||||
{
|
||||
"id": "Sink002",
|
||||
"name": "Sink002",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -105,6 +109,7 @@
|
||||
"activateFunction": "on_sink1_click"
|
||||
},
|
||||
{
|
||||
"id": "Sink003",
|
||||
"name": "Sink003",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -131,6 +136,7 @@
|
||||
"activateFunction": "on_sink1_click"
|
||||
},
|
||||
{
|
||||
"id": "Sink004",
|
||||
"name": "Sink004",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -157,6 +163,7 @@
|
||||
"activateFunction": "on_sink1_click"
|
||||
},
|
||||
{
|
||||
"id": "Sink005",
|
||||
"name": "Sink005",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -183,6 +190,7 @@
|
||||
"activateFunction": "on_sink1_click"
|
||||
},
|
||||
{
|
||||
"id": "Shower001",
|
||||
"name": "Shower001",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -209,6 +217,7 @@
|
||||
"activateFunction": "on_shower_click"
|
||||
},
|
||||
{
|
||||
"id": "Freezer001",
|
||||
"name": "Freezer001",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -235,6 +244,7 @@
|
||||
"activateFunction": "on_freezer_click"
|
||||
},
|
||||
{
|
||||
"id": "Boombox001",
|
||||
"name": "Boombox001",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -261,6 +271,7 @@
|
||||
"activateFunction": "on_boombox_click"
|
||||
},
|
||||
{
|
||||
"id": "WashingMachine001",
|
||||
"name": "WashingMachine001",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -287,6 +298,7 @@
|
||||
"activateFunction": "on_washing_machine1_click"
|
||||
},
|
||||
{
|
||||
"id": "Shelf001",
|
||||
"name": "Shelf001",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -313,6 +325,7 @@
|
||||
"activateFunction": "on_shelf_click"
|
||||
},
|
||||
{
|
||||
"id": "Stove001",
|
||||
"name": "Stove001",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -339,6 +352,7 @@
|
||||
"activateFunction": "on_stove1_click"
|
||||
},
|
||||
{
|
||||
"id": "Dryer001",
|
||||
"name": "Dryer001",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -365,6 +379,7 @@
|
||||
"activateFunction": "on_dryer1_click"
|
||||
},
|
||||
{
|
||||
"id": "Sink001",
|
||||
"name": "Sink001",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -391,6 +406,7 @@
|
||||
"activateFunction": "on_sink1_click"
|
||||
},
|
||||
{
|
||||
"id": "Door_Room_1_1_0_Leaf_001",
|
||||
"name": "Door_Room_1_1_0_Leaf_001",
|
||||
"texturePath": "resources/w/dorm2/interior_door_tex003.png",
|
||||
"meshPath": "resources/w/dorm2/Door_Room_1_1_0_Leaf_001.txt.bin",
|
||||
@@ -398,7 +414,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 1.1,
|
||||
"positionY": 0.0,
|
||||
"positionY": 0.9695000052452087,
|
||||
"positionZ": 10.0,
|
||||
"approachRadius": 0.89,
|
||||
"boundsMaxX": 0.01552116870880127,
|
||||
@@ -415,6 +431,7 @@
|
||||
"activateFunction": "on_locked_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Door_Room_1_-1_0_Leaf_001",
|
||||
"name": "Door_Room_1_-1_0_Leaf_001",
|
||||
"texturePath": "resources/w/dorm2/interior_door_tex003.png",
|
||||
"meshPath": "resources/w/dorm2/Door_Room_1_-1_0_Leaf_001.txt.bin",
|
||||
@@ -422,7 +439,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -1.1,
|
||||
"positionY": 0.0,
|
||||
"positionY": 0.9695000052452087,
|
||||
"positionZ": 10.0,
|
||||
"approachRadius": 0.8,
|
||||
"boundsMaxX": 0.10440409183502197,
|
||||
@@ -439,6 +456,7 @@
|
||||
"activateFunction": "on_locked_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Door_Room_-1_1_0_Leaf_001",
|
||||
"name": "Door_Room_-1_1_0_Leaf_001",
|
||||
"texturePath": "resources/w/dorm2/interior_door_tex003.png",
|
||||
"meshPath": "resources/w/dorm2/Door_Room_-1_1_0_Leaf_001.txt.bin",
|
||||
@@ -446,7 +464,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 1.1,
|
||||
"positionY": 0.0,
|
||||
"positionY": 0.9695000052452087,
|
||||
"positionZ": -10.0,
|
||||
"approachRadius": 0.8,
|
||||
"boundsMaxX": 0.05766594409942627,
|
||||
@@ -463,6 +481,7 @@
|
||||
"activateFunction": "on_locked_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Door_Room_-1_-1_0_Leaf_001",
|
||||
"name": "Door_Room_-1_-1_0_Leaf_001",
|
||||
"texturePath": "resources/w/dorm2/interior_door_tex003.png",
|
||||
"meshPath": "resources/w/dorm2/Door_Room_-1_-1_0_Leaf_001.txt.bin",
|
||||
@@ -470,7 +489,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -1.1,
|
||||
"positionY": 0.0,
|
||||
"positionY": 0.9695000052452087,
|
||||
"positionZ": -10.0,
|
||||
"approachRadius": 0.8,
|
||||
"boundsMaxX": 0.10906755924224854,
|
||||
@@ -487,6 +506,7 @@
|
||||
"activateFunction": "on_locked_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Door_Room_1_1_1_Leaf_001",
|
||||
"name": "Door_Room_1_1_1_Leaf_001",
|
||||
"texturePath": "resources/w/dorm2/interior_door_tex003.png",
|
||||
"meshPath": "resources/w/dorm2/Door_Room_1_1_1_Leaf_001.txt.bin",
|
||||
@@ -494,7 +514,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 1.1,
|
||||
"positionY": 0.0,
|
||||
"positionY": 0.9695000052452087,
|
||||
"positionZ": 15.7,
|
||||
"approachRadius": 0.8,
|
||||
"boundsMaxX": 0.046350955963134766,
|
||||
@@ -511,6 +531,7 @@
|
||||
"activateFunction": "on_locked_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Door_Room_1_-1_1_Leaf_001",
|
||||
"name": "Door_Room_1_-1_1_Leaf_001",
|
||||
"texturePath": "resources/w/dorm2/interior_door_tex003.png",
|
||||
"meshPath": "resources/w/dorm2/Door_Room_1_-1_1_Leaf_001.txt.bin",
|
||||
@@ -518,7 +539,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -1.1,
|
||||
"positionY": 0.0,
|
||||
"positionY": 0.9695000052452087,
|
||||
"positionZ": 15.7,
|
||||
"approachRadius": 0.800000011920929,
|
||||
"boundsMaxX": 0.12420153617858887,
|
||||
@@ -535,6 +556,7 @@
|
||||
"activateFunction": "on_locked_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Door_Utility_1_1_2_Leaf_001",
|
||||
"name": "Door_Utility_1_1_2_Leaf_001",
|
||||
"texturePath": "resources/w/dorm2/interior_door_tex003.png",
|
||||
"meshPath": "resources/w/dorm2/Door_Utility_1_1_2_Leaf_001.txt.bin",
|
||||
@@ -542,7 +564,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 1.1,
|
||||
"positionY": 0.0,
|
||||
"positionY": 0.9695000052452087,
|
||||
"positionZ": 19.95,
|
||||
"approachRadius": 0.8,
|
||||
"boundsMaxX": -0.050987482070922852,
|
||||
@@ -559,6 +581,7 @@
|
||||
"activateFunction": "on_locked_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Door_Utility_1_-1_2_Leaf_001",
|
||||
"name": "Door_Utility_1_-1_2_Leaf_001",
|
||||
"texturePath": "resources/w/dorm2/interior_door_tex003.png",
|
||||
"meshPath": "resources/w/dorm2/Door_Utility_1_-1_2_Leaf_001.txt.bin",
|
||||
@@ -566,7 +589,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -1.1,
|
||||
"positionY": 0.0,
|
||||
"positionY": 0.9695000052452087,
|
||||
"positionZ": 19.95,
|
||||
"approachRadius": 0.8,
|
||||
"boundsMaxX": 0.073349356651306152,
|
||||
@@ -583,6 +606,7 @@
|
||||
"activateFunction": "on_locked_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Door_Utility_-1_1_2_Leaf_001",
|
||||
"name": "Door_Utility_-1_1_2_Leaf_001",
|
||||
"texturePath": "resources/w/dorm2/interior_door_tex003.png",
|
||||
"meshPath": "resources/w/dorm2/Door_Utility_-1_1_2_Leaf_001.txt.bin",
|
||||
@@ -590,7 +614,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 1.1,
|
||||
"positionY": 0.0,
|
||||
"positionY": 0.9695000052452087,
|
||||
"positionZ": -19.95,
|
||||
"pivotX": 0.0,
|
||||
"pivotY": 0.0,
|
||||
@@ -599,6 +623,7 @@
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Door_Utility_-1_-1_2_Leaf_001",
|
||||
"name": "Door_Utility_-1_-1_2_Leaf_001",
|
||||
"texturePath": "resources/w/dorm2/interior_door_tex003.png",
|
||||
"meshPath": "resources/w/dorm2/Door_Utility_-1_-1_2_Leaf_001.txt.bin",
|
||||
@@ -606,7 +631,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -1.1,
|
||||
"positionY": 0.0,
|
||||
"positionY": 0.9695000052452087,
|
||||
"positionZ": -19.95,
|
||||
"pivotX": 0.0,
|
||||
"pivotY": 0.0,
|
||||
@@ -615,13 +640,14 @@
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Phone001",
|
||||
"name": "Phone001",
|
||||
"texturePath": "resources/w/dorm2/phone001_tex001.png",
|
||||
"meshPath": "resources/w/dorm2/phone001_001.txt.bin",
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 6.6644,
|
||||
"positionX": 6.6644004991889,
|
||||
"positionY": 0.9,
|
||||
"positionZ": -12.5262,
|
||||
"approachRadius": 0.6,
|
||||
@@ -640,6 +666,7 @@
|
||||
"activateFunction": "on_phone_pickup"
|
||||
},
|
||||
{
|
||||
"id": "Journal001",
|
||||
"name": "Journal001",
|
||||
"texturePath": "resources/w/dorm2/Book_Cover_tex002.png",
|
||||
"meshPath": "resources/w/dorm2/journal002_002.txt.bin",
|
||||
@@ -647,7 +674,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 5.84296,
|
||||
"positionY": 0.9,
|
||||
"positionY": 0.9284919999539852,
|
||||
"positionZ": -12.4661,
|
||||
"approachRadius": 0.6,
|
||||
"boundsMaxX": 0.17081403732299805,
|
||||
@@ -665,6 +692,7 @@
|
||||
"activateFunction": "on_journal_pickup"
|
||||
},
|
||||
{
|
||||
"id": "Bed001",
|
||||
"name": "Bed001",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -691,21 +719,23 @@
|
||||
"activateFunction": "on_bed_sleep"
|
||||
},
|
||||
{
|
||||
"id": "Music001",
|
||||
"name": "Music001",
|
||||
"texturePath": "resources/w/exterior/texAtlas002.png",
|
||||
"meshPath": "resources/w/dorm2/D_Music_004.txt.bin",
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 5.10067,
|
||||
"positionY": 0.91385,
|
||||
"positionZ": -11.9566,
|
||||
"positionX": 5.1006695008111,
|
||||
"positionY": 1.0181855017900467,
|
||||
"positionZ": -11.958324999397993,
|
||||
"approachRadius": 0.6,
|
||||
"scale": 1.0,
|
||||
"interactionRadius": 0.3,
|
||||
"activateFunction": ""
|
||||
},
|
||||
{
|
||||
"id": "Door_Bath_-1_1_1_Leaf_002",
|
||||
"name": "Door_Bath_-1_1_1_Leaf_002",
|
||||
"texturePath": "resources/w/dorm2/interior_door_tex003.png",
|
||||
"meshPath": "resources/w/dorm2/Door_Bath_-1_1_1_Leaf_002.txt.bin",
|
||||
@@ -713,7 +743,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 2.825,
|
||||
"positionY": 0.0,
|
||||
"positionY": 0.9695000052452087,
|
||||
"positionZ": -14.3,
|
||||
"pivotX": -0.6,
|
||||
"pivotY": 0.0,
|
||||
@@ -733,6 +763,7 @@
|
||||
"activateFunction": "on_player_bathroom_click"
|
||||
},
|
||||
{
|
||||
"id": "Door_Bath_-1_-1_1_Leaf_002",
|
||||
"name": "Door_Bath_-1_-1_1_Leaf_002",
|
||||
"texturePath": "resources/w/dorm2/interior_door_tex003.png",
|
||||
"meshPath": "resources/w/dorm2/Door_Bath_-1_-1_1_Leaf_002.txt.bin",
|
||||
@@ -740,7 +771,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -2.825,
|
||||
"positionY": 0.0,
|
||||
"positionY": 0.9695000052452087,
|
||||
"positionZ": -14.3,
|
||||
"approachRadius": 0.8,
|
||||
"boundsMaxX": 0.55439233779907227,
|
||||
@@ -757,6 +788,7 @@
|
||||
"activateFunction": "on_alik_bathroom_click"
|
||||
},
|
||||
{
|
||||
"id": "Door_Room_-1_1_1_Leaf_001",
|
||||
"name": "Door_Room_-1_1_1_Leaf_001",
|
||||
"texturePath": "resources/w/dorm2/interior_door_tex003.png",
|
||||
"meshPath": "resources/w/dorm2/Door_Room_-1_1_1_Leaf_001.txt.bin",
|
||||
@@ -764,7 +796,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 1.1,
|
||||
"positionY": 0.0,
|
||||
"positionY": 0.9695000052452087,
|
||||
"positionZ": -15.7,
|
||||
"pivotX": 0.0,
|
||||
"pivotY": 0.0,
|
||||
@@ -784,6 +816,7 @@
|
||||
"activateFunction": "on_player_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Door_Room_-1_-1_1_Leaf_001",
|
||||
"name": "Door_Room_-1_-1_1_Leaf_001",
|
||||
"texturePath": "resources/w/dorm2/interior_door_tex003.png",
|
||||
"meshPath": "resources/w/dorm2/Door_Room_-1_-1_1_Leaf_001.txt.bin",
|
||||
@@ -791,7 +824,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -1.1,
|
||||
"positionY": 0.0,
|
||||
"positionY": 0.9695000052452087,
|
||||
"positionZ": -15.7,
|
||||
"approachRadius": 0.8,
|
||||
"boundsMaxX": 0.13942182064056396,
|
||||
@@ -811,6 +844,7 @@
|
||||
"activateFunction": "on_alik_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Room_Cover_Bath_W_N_2_001",
|
||||
"name": "Room_Cover_Bath_W_N_2_001",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/dorm2/Room_Cover_Bath_W_N_2_002.txt.bin",
|
||||
@@ -818,13 +852,14 @@
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": -0.1,
|
||||
"positionZ": 0.0,
|
||||
"positionX": 2.8249999284744263,
|
||||
"positionY": 2.8500000476837157,
|
||||
"positionZ": -12.849999904632568,
|
||||
"scale": 1.0,
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Room_Cover_LivingRoom_W_N_2_001",
|
||||
"name": "Room_Cover_LivingRoom_W_N_2_001",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/dorm2/Room_Cover_LivingRoom_W_N_2_002.txt.bin",
|
||||
@@ -832,13 +867,14 @@
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": -0.1,
|
||||
"positionZ": 0.0,
|
||||
"positionX": 4.949999928474426,
|
||||
"positionY": 2.8500000476837157,
|
||||
"positionZ": -14.25,
|
||||
"scale": 1.0,
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Room_Cover_LivingRoom_W_S_2_001",
|
||||
"name": "Room_Cover_LivingRoom_W_S_2_001",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/dorm2/Room_Cover_LivingRoom_W_S_2_002.txt.bin",
|
||||
@@ -846,13 +882,14 @@
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": -0.1,
|
||||
"positionZ": 0.0,
|
||||
"positionX": -4.949999928474426,
|
||||
"positionY": 2.8500000476837157,
|
||||
"positionZ": -14.25,
|
||||
"scale": 1.0,
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Room_Cover_Main_Hall_And_Corridors_002",
|
||||
"name": "Room_Cover_Main_Hall_And_Corridors_002",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/dorm2/Room_Cover_Main_Hall_And_Corridors_002.txt.bin",
|
||||
@@ -861,12 +898,13 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": -0.1,
|
||||
"positionY": 2.8500000476837157,
|
||||
"positionZ": 0.0,
|
||||
"scale": 1.0,
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Room_Cover_Others_001",
|
||||
"name": "Room_Cover_Others_001",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/dorm2/Room_Cover_All_002.txt.bin",
|
||||
@@ -875,12 +913,13 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": -0.1,
|
||||
"positionZ": 0.0,
|
||||
"positionY": 2.8500000476837157,
|
||||
"positionZ": 4.250000476837158,
|
||||
"scale": 1.0,
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Room_Cover_Utility_W_N_3_001",
|
||||
"name": "Room_Cover_Utility_W_N_3_001",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/dorm2/Room_Cover_Utility_W_N_3_002.txt.bin",
|
||||
@@ -888,13 +927,14 @@
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": -0.1,
|
||||
"positionZ": 0.0,
|
||||
"positionX": 4.949999928474426,
|
||||
"positionY": 2.8500000476837157,
|
||||
"positionZ": -19.950000762939453,
|
||||
"scale": 1.0,
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Room_Cover_Utility_W_S_3_001",
|
||||
"name": "Room_Cover_Utility_W_S_3_001",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/dorm2/Room_Cover_Utility_W_S_3_002.txt.bin",
|
||||
@@ -902,13 +942,14 @@
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": -0.1,
|
||||
"positionZ": 0.0,
|
||||
"positionX": -4.949999928474426,
|
||||
"positionY": 2.8500000476837157,
|
||||
"positionZ": -19.950000762939453,
|
||||
"scale": 1.0,
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Roof",
|
||||
"name": "Roof",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/dorm2/Shadow_Roof001_002.txt.bin",
|
||||
@@ -919,7 +960,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": 0.1,
|
||||
"positionY": 3.2050000190734864,
|
||||
"positionZ": 0.0,
|
||||
"scale": 1.0,
|
||||
"interactionRadius": 0.0
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
{
|
||||
"objects": [
|
||||
{
|
||||
"id": "Container001",
|
||||
"name": "Container001",
|
||||
"texturePath": "resources/w/exterior/derbis001_tex001.png",
|
||||
"meshPath": "resources/w/exterior/Derbis_001.txt.bin",
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -26.8049,
|
||||
"positionY": 0.0,
|
||||
"positionZ": 9.11524,
|
||||
"positionX": -27.003390023612976,
|
||||
"positionY": 0.32889999728649855,
|
||||
"positionZ": 8.820399544944763,
|
||||
"approachRadius": 1.5,
|
||||
"boundsMaxX": 2.9518299102783203,
|
||||
"boundsMaxY": 0.5,
|
||||
@@ -25,15 +26,16 @@
|
||||
"activateFunction": "on_container_clicked"
|
||||
},
|
||||
{
|
||||
"id": "car001",
|
||||
"name": "car001",
|
||||
"texturePath": "resources/e/car4096blue_v002.png",
|
||||
"meshPath": "resources/e/car004.txt.bin",
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 90.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -10.5,
|
||||
"positionY": 0.55,
|
||||
"positionZ": -14.4195,
|
||||
"positionX": -10.503284412622452,
|
||||
"positionY": 0.9012498408555984,
|
||||
"positionZ": -14.861633367061614,
|
||||
"approachRadius": 0.5,
|
||||
"boundsMaxX": 0.8858480453491211,
|
||||
"boundsMaxY": 0.7,
|
||||
@@ -49,6 +51,7 @@
|
||||
"scale": 0.7
|
||||
},
|
||||
{
|
||||
"id": "car001wheels",
|
||||
"name": "car001wheels",
|
||||
"texturePath": "resources/w/exterior/Wheel_base003.png",
|
||||
"meshPath": "resources/w/exterior/wheels002.txt.bin",
|
||||
@@ -56,8 +59,8 @@
|
||||
"rotationY": 90.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -10.5,
|
||||
"positionY": 0.0,
|
||||
"positionZ": -14.4195,
|
||||
"positionY": 0.3359999924898147,
|
||||
"positionZ": -14.839499933242797,
|
||||
"approachRadius": 0.5,
|
||||
"boundsMaxX": 0,
|
||||
"boundsMaxY": 0.0,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"objects": [
|
||||
{
|
||||
"id": "Bookshelf002",
|
||||
"name": "Bookshelf002",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -27,6 +28,7 @@
|
||||
"castShadow": false
|
||||
},
|
||||
{
|
||||
"id": "Bookshelf003",
|
||||
"name": "Bookshelf003",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -53,6 +55,7 @@
|
||||
"castShadow": false
|
||||
},
|
||||
{
|
||||
"id": "Bookshelf004",
|
||||
"name": "Bookshelf004",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -79,6 +82,7 @@
|
||||
"castShadow": false
|
||||
},
|
||||
{
|
||||
"id": "Bookshelf005",
|
||||
"name": "Bookshelf005",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -105,15 +109,16 @@
|
||||
"castShadow": false
|
||||
},
|
||||
{
|
||||
"id": "Cake001",
|
||||
"name": "Cake001",
|
||||
"texturePath": "resources/w/exterior/texAtlas002.png",
|
||||
"meshPath": "resources/w/interior/D_Cake_005.txt.bin",
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0,
|
||||
"positionY": -5.0,
|
||||
"positionZ": 0,
|
||||
"positionX": -5.365539073944092,
|
||||
"positionY": 0.9888315200805664,
|
||||
"positionZ": 2.468366503715515,
|
||||
"approachRadius": 0.6,
|
||||
"boundsMaxX": 0.19605731964111328,
|
||||
"boundsMaxY": 0.4,
|
||||
@@ -131,6 +136,7 @@
|
||||
"castShadow": false
|
||||
},
|
||||
{
|
||||
"id": "Computer001",
|
||||
"name": "Computer001",
|
||||
"texturePath": "resources/w/interior/computer_texture002.png",
|
||||
"textureDarkandsPath": "resources/w/interior/computer_texture002_dark.png",
|
||||
@@ -138,9 +144,9 @@
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 5.0916,
|
||||
"positionY": 1.1534,
|
||||
"positionZ": 0.751629,
|
||||
"positionX": 5.01753252658844,
|
||||
"positionY": 1.353411484324932,
|
||||
"positionZ": 0.6829135021486282,
|
||||
"approachRadius": 1.2,
|
||||
"boundsMaxX": 0.6253643035888672,
|
||||
"boundsMaxY": 0.5,
|
||||
@@ -155,15 +161,16 @@
|
||||
"activateFunction": "on_computer_clicked"
|
||||
},
|
||||
{
|
||||
"id": "Knife001",
|
||||
"name": "Knife001",
|
||||
"texturePath": "resources/w/gg/Props.png",
|
||||
"meshPath": "resources/w/interior/Knife_lay001_004.txt.bin",
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -4.8327,
|
||||
"positionX": -4.959765496635623,
|
||||
"positionY": 0.93551,
|
||||
"positionZ": 2.2418,
|
||||
"positionZ": 2.369899506953731,
|
||||
"approachRadius": 1.4,
|
||||
"boundsMaxX": 0.30867958068847656,
|
||||
"boundsMaxY": 0.4,
|
||||
@@ -177,6 +184,7 @@
|
||||
"castShadowNight" : false
|
||||
},
|
||||
{
|
||||
"id": "Book001",
|
||||
"name": "Book001",
|
||||
"texturePath": "resources/w/interior/Book_Cover_tex003.png",
|
||||
"meshPath": "resources/w/interior/book002_002.txt.bin",
|
||||
@@ -184,7 +192,7 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 1.84795,
|
||||
"positionY": 0.6595,
|
||||
"positionY": 0.6809705001562834,
|
||||
"positionZ": 2.90552,
|
||||
"approachRadius": 0.6,
|
||||
"boundsMaxX": 0.2350165843963623,
|
||||
@@ -202,6 +210,7 @@
|
||||
"castShadowNight" : false
|
||||
},
|
||||
{
|
||||
"id": "Bookshelf001",
|
||||
"name": "Bookshelf001",
|
||||
"texturePath": "resources/transparent.png",
|
||||
"meshPath": "resources/w/Cube_001.txt.bin",
|
||||
@@ -228,6 +237,7 @@
|
||||
"castShadow": false
|
||||
},
|
||||
{
|
||||
"id": "ReportCard001",
|
||||
"name": "ReportCard001",
|
||||
"texturePath": "resources/w/exterior/texAtlas002.png",
|
||||
"meshPath": "resources/w/interior/D_report_cardGG_005.txt.bin",
|
||||
@@ -252,6 +262,7 @@
|
||||
"activateFunction": "on_report_card_pickup"
|
||||
},
|
||||
{
|
||||
"id": "Note001",
|
||||
"name": "Note001",
|
||||
"texturePath": "resources/w/interior/note001_tex003.png",
|
||||
"meshPath": "resources/w/interior/note001_002.txt.bin",
|
||||
@@ -276,15 +287,16 @@
|
||||
"activateFunction": "on_note_pickup"
|
||||
},
|
||||
{
|
||||
"id": "car001",
|
||||
"name": "car001",
|
||||
"texturePath": "resources/e/car4096blue_v002.png",
|
||||
"meshPath": "resources/e/car004.txt.bin",
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 90.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -10.5,
|
||||
"positionY": -5.0,
|
||||
"positionZ": -14.4195,
|
||||
"positionX": -10.503284412622452,
|
||||
"positionY": -4.648750159144401,
|
||||
"positionZ": -14.861633367061614,
|
||||
"approachRadius": 0.6,
|
||||
"boundsMaxX": 0.0,
|
||||
"boundsMaxY": 0.0,
|
||||
@@ -299,6 +311,7 @@
|
||||
"scale": 0.7
|
||||
},
|
||||
{
|
||||
"id": "car001wheels",
|
||||
"name": "car001wheels",
|
||||
"texturePath": "resources/w/exterior/Wheel_base003.png",
|
||||
"meshPath": "resources/w/exterior/wheels002.txt.bin",
|
||||
@@ -306,8 +319,8 @@
|
||||
"rotationY": 90.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -10.5,
|
||||
"positionY": -5.0,
|
||||
"positionZ": -14.4195,
|
||||
"positionY": -4.664000007510185,
|
||||
"positionZ": -14.839499933242797,
|
||||
"approachRadius": 0.6,
|
||||
"boundsMaxX": 0.0,
|
||||
"boundsMaxY": 0.0,
|
||||
@@ -322,6 +335,7 @@
|
||||
"scale": 0.7
|
||||
},
|
||||
{
|
||||
"id": "Room_N_2_Leaf001",
|
||||
"name": "Room_N_2_Leaf001",
|
||||
"texturePath": "resources/w/interior/uni_interior_door_tex001.png",
|
||||
"meshPath": "resources/w/interior/outputRoom_N_2_Leaf001.txt.bin",
|
||||
@@ -330,7 +344,7 @@
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 1.5,
|
||||
"positionY": 0.975,
|
||||
"positionZ": 6.965,
|
||||
"positionZ": 6.400000002384186,
|
||||
"approachRadius": 0.8,
|
||||
"boundsMaxX": 0.06785714626312256,
|
||||
"boundsMaxY": 1.0,
|
||||
@@ -349,6 +363,7 @@
|
||||
"activateFunction": "on_library_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Room_N_1_Leaf001",
|
||||
"name": "Room_N_1_Leaf001",
|
||||
"texturePath": "resources/w/interior/uni_interior_door_tex001.png",
|
||||
"meshPath": "resources/w/interior/outputRoom_N_1_Leaf001.txt.bin",
|
||||
@@ -357,7 +372,7 @@
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 1.5,
|
||||
"positionY": 0.975,
|
||||
"positionZ": -1.035,
|
||||
"positionZ": -1.5999999976158141,
|
||||
"approachRadius": 0.8,
|
||||
"boundsMaxX": 0.10772454738616943,
|
||||
"boundsMaxY": 1.0,
|
||||
@@ -376,6 +391,7 @@
|
||||
"activateFunction": "on_n2_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Room_S_1_Leaf001",
|
||||
"name": "Room_S_1_Leaf001",
|
||||
"texturePath": "resources/w/interior/uni_interior_door_tex001.png",
|
||||
"meshPath": "resources/w/interior/outputRoom_S_1_Leaf001.txt.bin",
|
||||
@@ -384,7 +400,7 @@
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -1.5,
|
||||
"positionY": 0.975,
|
||||
"positionZ": -1.035,
|
||||
"positionZ": -1.5999999976158141,
|
||||
"approachRadius": 0.8,
|
||||
"boundsMaxX": 0.12115073204040527,
|
||||
"boundsMaxY": 1.0,
|
||||
@@ -403,6 +419,7 @@
|
||||
"activateFunction": "on_s2_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Room_S_2_Leaf001",
|
||||
"name": "Room_S_2_Leaf001",
|
||||
"texturePath": "resources/w/interior/uni_interior_door_tex001.png",
|
||||
"meshPath": "resources/w/interior/outputRoom_S_2_Leaf001.txt.bin",
|
||||
@@ -411,7 +428,7 @@
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -1.5,
|
||||
"positionY": 0.975,
|
||||
"positionZ": 6.965,
|
||||
"positionZ": 6.400000002384186,
|
||||
"approachRadius": 0.8,
|
||||
"boundsMaxX": 0.09747374057769775,
|
||||
"boundsMaxY": 1.0,
|
||||
@@ -430,15 +447,16 @@
|
||||
"activateFunction": "on_teachers_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Hall_Leaf001",
|
||||
"name": "Hall_Leaf001",
|
||||
"texturePath": "resources/w/interior/uni_interior_door_tex001.png",
|
||||
"meshPath": "resources/w/interior/outputHall_Leaf001.txt.bin",
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.565,
|
||||
"positionX": 0.0,
|
||||
"positionY": 0.975,
|
||||
"positionZ": 8,
|
||||
"positionZ": 8.000001000240445,
|
||||
"approachRadius": 0.9,
|
||||
"boundsMaxX": 0.6243956089019775,
|
||||
"boundsMaxY": 1.0,
|
||||
@@ -457,6 +475,7 @@
|
||||
"activateFunction": "on_hall_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Room_S_0_Leaf001",
|
||||
"name": "Room_S_0_Leaf001",
|
||||
"texturePath": "resources/w/interior/uni_interior_door_tex001.png",
|
||||
"meshPath": "resources/w/interior/outputRoom_S_0_Leaf001.txt.bin",
|
||||
@@ -465,7 +484,7 @@
|
||||
"rotationZ": 0.0,
|
||||
"positionX": -1.5,
|
||||
"positionY": 0.975,
|
||||
"positionZ": -9.035,
|
||||
"positionZ": -9.599999020778657,
|
||||
"approachRadius": 0.8,
|
||||
"boundsMaxX": 0.10914039611816406,
|
||||
"boundsMaxY": 1.0,
|
||||
@@ -484,6 +503,7 @@
|
||||
"activateFunction": "on_s1_door_click"
|
||||
},
|
||||
{
|
||||
"id": "Room_Cover_Corridor_001",
|
||||
"name": "Room_Cover_Corridor_001",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/interior/Room_Cover_Corridor_003.txt.bin",
|
||||
@@ -491,9 +511,9 @@
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": -5.0,
|
||||
"positionZ": 0.0,
|
||||
"positionX": 2.2500000596046448,
|
||||
"positionY": 2.4499998092651367,
|
||||
"positionZ": -3.999999761581421,
|
||||
"scale": 1.0,
|
||||
"pivotX": 0.0,
|
||||
"pivotY": 0.0,
|
||||
@@ -501,6 +521,7 @@
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Room_Cover_Main_Hall_001",
|
||||
"name": "Room_Cover_Main_Hall_001",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/interior/Room_Cover_Main_Hall_003.txt.bin",
|
||||
@@ -509,8 +530,8 @@
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": -5.0,
|
||||
"positionZ": 0.0,
|
||||
"positionY": 2.4499998092651367,
|
||||
"positionZ": 12.0,
|
||||
"scale": 1.0,
|
||||
"pivotX": 0.0,
|
||||
"pivotY": 0.0,
|
||||
@@ -518,6 +539,7 @@
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Room_Cover_South_1_001",
|
||||
"name": "Room_Cover_South_1_001",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/interior/Room_Cover_South_1_003.txt.bin",
|
||||
@@ -525,9 +547,9 @@
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": -5.0,
|
||||
"positionZ": 0.0,
|
||||
"positionX": -3.7500000596046448,
|
||||
"positionY": 2.4499998092651367,
|
||||
"positionZ": -12.0,
|
||||
"scale": 1.0,
|
||||
"pivotX": 0.0,
|
||||
"pivotY": 0.0,
|
||||
@@ -535,6 +557,7 @@
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Room_Cover_North_2_001",
|
||||
"name": "Room_Cover_North_2_001",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/interior/Room_Cover_North_2_003.txt.bin",
|
||||
@@ -542,9 +565,9 @@
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": -5.0,
|
||||
"positionZ": 0.0,
|
||||
"positionX": 3.7500000596046448,
|
||||
"positionY": 2.4499998092651367,
|
||||
"positionZ": -4.000000048428774,
|
||||
"scale": 1.0,
|
||||
"pivotX": 0.0,
|
||||
"pivotY": 0.0,
|
||||
@@ -552,6 +575,7 @@
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Room_Cover_South_2_001",
|
||||
"name": "Room_Cover_South_2_001",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/interior/Room_Cover_South_2_003.txt.bin",
|
||||
@@ -559,9 +583,9 @@
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": -5.0,
|
||||
"positionZ": 0.0,
|
||||
"positionX": -3.7500000596046448,
|
||||
"positionY": 2.4499998092651367,
|
||||
"positionZ": -4.000000048428774,
|
||||
"scale": 1.0,
|
||||
"pivotX": 0.0,
|
||||
"pivotY": 0.0,
|
||||
@@ -569,6 +593,7 @@
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Room_Cover_North_3_001",
|
||||
"name": "Room_Cover_North_3_001",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/interior/Room_Cover_North_3_003.txt.bin",
|
||||
@@ -576,9 +601,9 @@
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": -5.0,
|
||||
"positionZ": 0.0,
|
||||
"positionX": 3.7500000596046448,
|
||||
"positionY": 2.4499998092651367,
|
||||
"positionZ": 4.000000048428774,
|
||||
"scale": 1.0,
|
||||
"pivotX": 0.0,
|
||||
"pivotY": 0.0,
|
||||
@@ -586,6 +611,7 @@
|
||||
"interactionRadius": 0.0
|
||||
},
|
||||
{
|
||||
"id": "Room_Cover_South_3_001",
|
||||
"name": "Room_Cover_South_3_001",
|
||||
"texturePath": "resources/black.png",
|
||||
"meshPath": "resources/w/interior/Room_Cover_South_3_003.txt.bin",
|
||||
@@ -593,9 +619,9 @@
|
||||
"rotationX": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"rotationZ": 0.0,
|
||||
"positionX": 0.0,
|
||||
"positionY": -5.0,
|
||||
"positionZ": 0.0,
|
||||
"positionX": -3.7500000596046448,
|
||||
"positionY": 2.4499998092651367,
|
||||
"positionZ": 4.000000048428774,
|
||||
"scale": 1.0,
|
||||
"pivotX": 0.0,
|
||||
"pivotY": 0.0,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{
|
||||
"id": "main_hall",
|
||||
"positionX": -3.1,
|
||||
"positionY": 6.0,
|
||||
"positionY": 4.8,
|
||||
"positionZ": 0.0,
|
||||
"directionX": 0.0,
|
||||
"directionY": -1.0,
|
||||
@@ -20,7 +20,7 @@
|
||||
"limitX": 3.75,
|
||||
"limitY": 2.75,
|
||||
"positionX": 4.95,
|
||||
"positionY": 3.0,
|
||||
"positionY": 3.6,
|
||||
"positionZ": -14.25,
|
||||
"directionX": 0.0,
|
||||
"directionY": -1.0,
|
||||
@@ -55,7 +55,7 @@
|
||||
"limitX": 3.75,
|
||||
"limitY": 2.75,
|
||||
"positionX": -4.95,
|
||||
"positionY": 4.0,
|
||||
"positionY": 4.2,
|
||||
"positionZ": -19.95,
|
||||
"directionX": 0.0,
|
||||
"directionY": -1.0,
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "uni_exterior",
|
||||
"gameObjects": "resources/w/shelter/game_objects.json",
|
||||
"interactiveObjects": "resources/w/shelter/interactive_objects.json",
|
||||
"npcs": "resources/config/npcs_battle_zone.json",
|
||||
"dialogues": "resources/dialogue/battle_zone_dialogues.json",
|
||||
"navigation": [
|
||||
"resources/navigation/dorm0_large.json"
|
||||
],
|
||||
"script": "resources/start_battle_zone.lua",
|
||||
"playerPosition": [-6, 0, 12.8]
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"id": "location_dorm",
|
||||
"gameObjects": "resources/config/gameobjects_dorm_new_x.json",
|
||||
"interactiveObjects": "resources/config/interactive_objects_dorm_x.json",
|
||||
"npcs": "resources/config/npcs_dorm.json",
|
||||
"dialogues": "resources/dialogue/dorm_dialogues004.json",
|
||||
"navigation": [
|
||||
"resources/navigation/dorm3_bca.txt",
|
||||
"resources/navigation/dorm3_ca.txt",
|
||||
"resources/navigation/dorm3_ba.txt",
|
||||
"resources/navigation/dorm3_a.txt",
|
||||
"resources/navigation/dorm3_b.txt",
|
||||
"resources/navigation/dorm3_all_open.txt"
|
||||
],
|
||||
"script": "resources/start_dorm.lua",
|
||||
"teleports": "resources/config/teleports_dorm.json",
|
||||
"triggerZones": "resources/config/trigger_zones_dorm.json",
|
||||
"lights": "resources/config/lights_dorm.json",
|
||||
"playerPosition": [6.76345, 0, -14.6022],
|
||||
"taxi": {
|
||||
"triggerPosition": [-19.0, 0, 0],
|
||||
"waypoints": [
|
||||
[-20.85, 0, 30.0],
|
||||
[-19.35, 0, 24.0],
|
||||
[-19.35, 0, 14.0]
|
||||
],
|
||||
"initialPosition": [-20.85, 0, 64],
|
||||
"initialRotation": 0,
|
||||
"waypointReachRadius": 5
|
||||
},
|
||||
"lockInteractiveObjectsDuringTutorial": true
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"id": "uni_exterior",
|
||||
"gameObjects": "resources/config/gameobjects_uni_exterior_x.json",
|
||||
"interactiveObjects": "resources/config/interactive_objects_uni_exterior_x.json",
|
||||
"npcs": "resources/config/npcs_uni_exterior.json",
|
||||
"dialogues": "resources/dialogue/uni_exterior_dialogues003.json",
|
||||
"navigation": [
|
||||
"resources/navigation/uni_exterior3_trees_car.txt",
|
||||
"resources/navigation/uni_exterior3_trees.txt"
|
||||
],
|
||||
"script": "resources/start_uni_exterior.lua",
|
||||
"teleports": "resources/config/teleports_uni_exterior.json",
|
||||
"triggerZones": "resources/config/trigger_zones_uni_exterior.json",
|
||||
"lights": "resources/config/lights_uni_exterior.json",
|
||||
"playerPosition": [5, 0, -18.4],
|
||||
"taxi": {
|
||||
"triggerPosition": [-17.6, 0.05, -45],
|
||||
"waypoints": [
|
||||
[-17.6, 0.05, -90.0],
|
||||
[-17.6, 0.05, -75.0],
|
||||
[-17.6, 0.05, -55.0]
|
||||
],
|
||||
"initialPosition": [-17.6, 0.05, -100],
|
||||
"initialRotation": 180,
|
||||
"waypointReachRadius": 5
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"id": "uni_interior",
|
||||
"gameObjects": "resources/config/gameobjects_uni_interior_x.json",
|
||||
"interactiveObjects": "resources/config/interactive_objects_uni_interior_x.json",
|
||||
"npcs": "resources/config/npcs_uni_interior.json",
|
||||
"dialogues": "resources/dialogue/uni_interior_dialogues_010.json",
|
||||
"navigation": [
|
||||
"resources/navigation/uni_interior4_unlocked_n2.txt",
|
||||
"resources/navigation/uni_interior3_n2_hall.txt",
|
||||
"resources/navigation/uni_interior4_n2_lr_hall.txt",
|
||||
"resources/navigation/uni_interior4_n2_lr_tr_hall.txt",
|
||||
"resources/navigation/uni_interior3_n2_lr_tr_hall_aiperi.txt",
|
||||
"resources/navigation/uni_interior3_darklands_all_open.txt",
|
||||
"resources/navigation/uni_interior4_unlocked_hall.txt",
|
||||
"resources/navigation/uni_interior4_unlocked_n3.txt",
|
||||
"resources/navigation/uni_interior4_unlocked_s1.txt",
|
||||
"resources/navigation/uni_interior4_unlocked_s2.txt",
|
||||
"resources/navigation/uni_interior4_unlocked_s3.txt",
|
||||
"resources/navigation/uni_interior4_unlocked_s3_s1.txt",
|
||||
"resources/navigation/uni_interior4_unlocked_s3_hall.txt",
|
||||
"resources/navigation/uni_interior4_unlocked_s3_n3.txt",
|
||||
"resources/navigation/uni_interior4_unlocked_s3_n2.txt",
|
||||
"resources/navigation/uni_interior4_unlocked_s3_s2.txt",
|
||||
"resources/navigation/uni_interior4_locked.txt"
|
||||
],
|
||||
"script": "resources/start_uni_interior.lua",
|
||||
"teleports": "resources/config/teleports_uni_interior.json",
|
||||
"triggerZones": "resources/config/trigger_zones_uni_interior.json",
|
||||
"lights": "resources/config/lights_uni_interior.json",
|
||||
"playerPosition": [0.942694, 0, -9.63104]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"npcs": [
|
||||
]
|
||||
}
|
||||
@@ -145,7 +145,7 @@
|
||||
"canAttack": true
|
||||
},
|
||||
{
|
||||
"id": "npc_02_woman",
|
||||
"id": "npc_altynai",
|
||||
"name": "Алтынай",
|
||||
"animationIdlePath": "resources/w/girl/girl_idle001_small.anim",
|
||||
"animationWalkPath": "resources/w/girl/girl_walk010_small.anim",
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"quests": [
|
||||
]
|
||||
}
|
||||
+318
-1206
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,252 @@
|
||||
{
|
||||
"localState": {
|
||||
"locations": {
|
||||
"uni_exterior": {
|
||||
"cameraAzimuth": -2.3499999046325684,
|
||||
"cameraInclination": 1.103600025177002
|
||||
}
|
||||
}
|
||||
},
|
||||
"networkState": {
|
||||
"campaignId": "battle_zone",
|
||||
"chatHistory": [
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
],
|
||||
"chatPreviewMsg": [
|
||||
"",
|
||||
"",
|
||||
""
|
||||
],
|
||||
"chatUnread": [
|
||||
true,
|
||||
true,
|
||||
true
|
||||
],
|
||||
"currentLocationId": "",
|
||||
"globalFloats": {
|
||||
"player_hp": 200.0
|
||||
},
|
||||
"globalInts": {},
|
||||
"inventory": {
|
||||
"items": []
|
||||
},
|
||||
"isDarklands": false,
|
||||
"isDawn": false,
|
||||
"isNight": false,
|
||||
"locations": {
|
||||
"uni_exterior": {
|
||||
"dialogue": {
|
||||
"active": false
|
||||
},
|
||||
"interactiveObjects": {
|
||||
"intBin_Cans": {
|
||||
"alpha": 1.0,
|
||||
"isActive": true,
|
||||
"isAnimating": false,
|
||||
"positionX": 0.6000000238418579,
|
||||
"positionY": 0.45736101269721985,
|
||||
"positionZ": 3.8499999046325684,
|
||||
"rotationY": 0.0,
|
||||
"scale": 1.0
|
||||
},
|
||||
"intBin_Plastic": {
|
||||
"alpha": 1.0,
|
||||
"isActive": true,
|
||||
"isAnimating": false,
|
||||
"positionX": 1.399999976158142,
|
||||
"positionY": 0.45736101269721985,
|
||||
"positionZ": 3.8499999046325684,
|
||||
"rotationY": 0.0,
|
||||
"scale": 1.0
|
||||
},
|
||||
"intBin_Waste_A": {
|
||||
"alpha": 1.0,
|
||||
"isActive": true,
|
||||
"isAnimating": false,
|
||||
"positionX": 2.200000047683716,
|
||||
"positionY": 0.45736101269721985,
|
||||
"positionZ": 3.8499999046325684,
|
||||
"rotationY": 0.0,
|
||||
"scale": 1.0
|
||||
},
|
||||
"intBin_Waste_B": {
|
||||
"alpha": 1.0,
|
||||
"isActive": true,
|
||||
"isAnimating": false,
|
||||
"positionX": 3.0,
|
||||
"positionY": 0.45736101269721985,
|
||||
"positionZ": 3.8499999046325684,
|
||||
"rotationY": 0.0,
|
||||
"scale": 1.0
|
||||
},
|
||||
"intRoof": {
|
||||
"alpha": 1.0,
|
||||
"isActive": true,
|
||||
"isAnimating": false,
|
||||
"positionX": 0.0,
|
||||
"positionY": 3.200000047683716,
|
||||
"positionZ": 0.0,
|
||||
"rotationY": 0.0,
|
||||
"scale": 1.0
|
||||
},
|
||||
"intVending.00": {
|
||||
"alpha": 1.0,
|
||||
"isActive": true,
|
||||
"isAnimating": false,
|
||||
"positionX": -1.0,
|
||||
"positionY": 0.9150000214576721,
|
||||
"positionZ": -3.9000000953674316,
|
||||
"rotationY": 0.0,
|
||||
"scale": 1.0
|
||||
},
|
||||
"intVending.01": {
|
||||
"alpha": 1.0,
|
||||
"isActive": true,
|
||||
"isAnimating": false,
|
||||
"positionX": 0.0,
|
||||
"positionY": 0.9150000214576721,
|
||||
"positionZ": -3.9000000953674316,
|
||||
"rotationY": 0.0,
|
||||
"scale": 1.0
|
||||
},
|
||||
"intVending.02": {
|
||||
"alpha": 1.0,
|
||||
"isActive": true,
|
||||
"isAnimating": false,
|
||||
"positionX": 1.0,
|
||||
"positionY": 0.9150000214576721,
|
||||
"positionZ": -3.9000000953674316,
|
||||
"rotationY": 0.0,
|
||||
"scale": 1.0
|
||||
}
|
||||
},
|
||||
"npcs": {},
|
||||
"scriptGlobals": {},
|
||||
"state": {
|
||||
"activeNavigationIndex": 0,
|
||||
"targetInteractNpcId": "",
|
||||
"targetInteractiveObjectId": "",
|
||||
"targetTeleportZoneId": "",
|
||||
"taxi": {
|
||||
"arrivedCallbackCalled": false,
|
||||
"car": {
|
||||
"currentWaypoint": 0,
|
||||
"mode": 1,
|
||||
"position": [
|
||||
-100.0,
|
||||
-100.0,
|
||||
-100.0
|
||||
],
|
||||
"rotation": 0.0,
|
||||
"steeringAngle": 0.0,
|
||||
"velocity": 0.0,
|
||||
"waypoints": [],
|
||||
"wheelAngle": 0.0
|
||||
}
|
||||
}
|
||||
},
|
||||
"teleportZones": {},
|
||||
"triggerZones": {}
|
||||
}
|
||||
},
|
||||
"money": 5500,
|
||||
"playerHp": 200.0,
|
||||
"playerMaxHp": 200.0,
|
||||
"players": {
|
||||
"player2": {
|
||||
"animationFrame": 0.0,
|
||||
"attackTargetId": "",
|
||||
"attack_cooldown": 0.0,
|
||||
"battle_state": 0,
|
||||
"currentState": 0,
|
||||
"currentWaypointIndex": 0,
|
||||
"enabled": true,
|
||||
"faceTargetId": "",
|
||||
"facingAngle": 0.0,
|
||||
"homeDriftCheckTimer": 5.0,
|
||||
"homePosition": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"hp": 200.0,
|
||||
"pathWaypoints": [],
|
||||
"position": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"requestedWalkTarget": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"showWeapon": true,
|
||||
"targetFacingAngle": 0.0,
|
||||
"visibleRange": 6.0,
|
||||
"walkTarget": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
},
|
||||
"player": {
|
||||
"animationFrame": 0.0,
|
||||
"attackTargetId": "",
|
||||
"attack_cooldown": 0.0,
|
||||
"battle_state": 0,
|
||||
"currentState": 0,
|
||||
"currentWaypointIndex": 0,
|
||||
"enabled": true,
|
||||
"faceTargetId": "",
|
||||
"facingAngle": 0.0,
|
||||
"homeDriftCheckTimer": 5.0,
|
||||
"homePosition": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"hp": 200.0,
|
||||
"pathWaypoints": [
|
||||
[
|
||||
-6.025001525878906,
|
||||
0.0,
|
||||
12.775001525878906
|
||||
]
|
||||
],
|
||||
"position": [
|
||||
-6.0,
|
||||
0.0,
|
||||
12.800000190734863
|
||||
],
|
||||
"requestedWalkTarget": [
|
||||
-6.0,
|
||||
0.0,
|
||||
12.800000190734863
|
||||
],
|
||||
"showWeapon": true,
|
||||
"targetFacingAngle": 0.0,
|
||||
"visibleRange": 6.0,
|
||||
"walkTarget": [
|
||||
-6.025001525878906,
|
||||
0.0,
|
||||
12.775001525878906
|
||||
]
|
||||
}
|
||||
},
|
||||
"questJournal": {
|
||||
"quests": []
|
||||
},
|
||||
"savedAt": "2026-11-05 17:43",
|
||||
"schemaVersion": 2,
|
||||
"taxiIsCalled": false,
|
||||
"tutorialJournalScreenOpened": false,
|
||||
"tutorialNeedOpenTaxiScreen": false,
|
||||
"tutorialPhoneChatScreenOpened": false,
|
||||
"tutorialStep": 0,
|
||||
"tutorialTaxiHintDone": false
|
||||
},
|
||||
"persistenceVersion": 1
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"dialogues": [
|
||||
]
|
||||
}
|
||||
@@ -2276,14 +2276,14 @@
|
||||
"en": "And maybe she will even give me some difficult assignment."
|
||||
},
|
||||
{
|
||||
"key": "Я даже уверена, она меня ищет. Она хочет мне какое-то задание дать.",
|
||||
"ru": "Я даже уверена, она меня ищет. Она хочет мне какое-то задание дать.",
|
||||
"en": "I'm even sure she's looking for me. She wants to give me some kind of assignment."
|
||||
"key": "Я уверена, она меня ищет. Она хочет мне какое-то задание дать.",
|
||||
"ru": "Я уверена, она меня ищет. Она хочет мне какое-то задание дать.",
|
||||
"en": "I'm sure she's looking for me. She wants to give me some kind of assignment."
|
||||
},
|
||||
{
|
||||
"key": "Пока ты не принесешь мне нож из учительской, никуда я тебя не выпущу. Ошо!",
|
||||
"ru": "Пока ты не принесешь мне нож из учительской, никуда я тебя не выпущу. Ошо!",
|
||||
"en": "Until you bring me a knife from the teachers' room, I won't let you go anywhere."
|
||||
"en": "Until you bring me a knife from the teachers' room, I won't let you go anywhere. Osho!"
|
||||
},
|
||||
{
|
||||
"key": "Я слышала она не смогла сдать курсовую по манасоведению.",
|
||||
@@ -2293,7 +2293,7 @@
|
||||
{
|
||||
"key": "Она прыгнула с окна и разбилась насмерть деп.",
|
||||
"ru": "Она прыгнула с окна и разбилась насмерть деп.",
|
||||
"en": "She jumped from the window and fell to her death, they said."
|
||||
"en": "She jumped from the window and fell to her death, dep."
|
||||
},
|
||||
{
|
||||
"key": "Да она надоела, все время скафнит.",
|
||||
@@ -2308,7 +2308,7 @@
|
||||
{
|
||||
"key": "Так что жду тебя в универе! Не вздумай прогулять! Ошо!",
|
||||
"ru": "Так что жду тебя в универе! Не вздумай прогулять! Ошо!",
|
||||
"en": "So I'm waiting for you at the university! Don't even think about skipping!"
|
||||
"en": "So I'm waiting for you at the university! Don't even think about skipping! Osho!"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -412,6 +412,70 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "dialog_chat_aiperi003",
|
||||
"start": "line_1",
|
||||
"nodes": [
|
||||
{
|
||||
"id": "line_1",
|
||||
"type": "Line",
|
||||
"speaker": "Бекзат",
|
||||
"portrait": "resources/dialogue/portrait_phone.png",
|
||||
"text": "Айпери ты куда убежала?",
|
||||
"next": "line_2",
|
||||
"chatBubble": "out"
|
||||
},
|
||||
{
|
||||
"id": "line_2",
|
||||
"type": "Line",
|
||||
"speaker": "Айпери",
|
||||
"portrait": "resources/dialogue/portrait_phone.png",
|
||||
"text": "Ты достал уже, я не могу тебя ждать вечно! Возишься как сонная муха.",
|
||||
"next": "line_3",
|
||||
"chatBubble": "in"
|
||||
},
|
||||
{
|
||||
"id": "line_3",
|
||||
"type": "Line",
|
||||
"speaker": "Айпери",
|
||||
"portrait": "resources/dialogue/portrait_phone.png",
|
||||
"text": "У меня нет времени ждать тебя, мне уже пора на курсы ехать.",
|
||||
"next": "line_4",
|
||||
"chatBubble": "in"
|
||||
},
|
||||
{
|
||||
"id": "line_4",
|
||||
"type": "Line",
|
||||
"speaker": "Бекзат",
|
||||
"portrait": "resources/dialogue/portrait_phone.png",
|
||||
"text": "Так когда я тебе нож верну?",
|
||||
"next": "line_5",
|
||||
"chatBubble": "out"
|
||||
},
|
||||
{
|
||||
"id": "line_5",
|
||||
"type": "Line",
|
||||
"speaker": "Айпери",
|
||||
"portrait": "resources/dialogue/portrait_phone.png",
|
||||
"text": "Приходи завтра в универ! Я каждый день в унике с раннего утра.",
|
||||
"next": "line_6",
|
||||
"chatBubble": "in"
|
||||
},
|
||||
{
|
||||
"id": "line_6",
|
||||
"type": "Line",
|
||||
"speaker": "Бекзат",
|
||||
"portrait": "resources/dialogue/portrait_phone.png",
|
||||
"text": "Хорошо, встретимся завтра.",
|
||||
"next": "end_1",
|
||||
"chatBubble": "out"
|
||||
},
|
||||
{
|
||||
"id": "end_1",
|
||||
"type": "End"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "dialog_car001",
|
||||
"start": "line_1",
|
||||
|
||||
@@ -293,14 +293,6 @@
|
||||
"speaker": "Бекзат",
|
||||
"portrait": "resources/dialogue/portrait_hero_neutral.png",
|
||||
"text": "Почему?",
|
||||
"next": "line_30"
|
||||
},
|
||||
{
|
||||
"id": "line_30",
|
||||
"type": "Line",
|
||||
"speaker": "Айпери",
|
||||
"portrait": "resources/dialogue/portrait_aiperi.png",
|
||||
"text": "Она опять будет скафнить.",
|
||||
"next": "line_25"
|
||||
},
|
||||
{
|
||||
@@ -308,7 +300,7 @@
|
||||
"type": "Line",
|
||||
"speaker": "Айпери",
|
||||
"portrait": "resources/dialogue/portrait_aiperi.png",
|
||||
"text": "Я даже уверена, она меня ищет. Она хочет мне какое-то задание дать.",
|
||||
"text": "Я уверена, она меня ищет. Она хочет мне какое-то задание дать.",
|
||||
"next": "line_26"
|
||||
},
|
||||
{
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,11 @@
|
||||
attribute vec3 vPosition;
|
||||
attribute vec2 vTexCoord;
|
||||
#ifdef INSTANCED
|
||||
attribute vec4 iModel0;
|
||||
attribute vec4 iModel1;
|
||||
attribute vec4 iModel2;
|
||||
attribute vec4 iModel3;
|
||||
#endif
|
||||
varying vec2 texCoord;
|
||||
varying float fogDistance;
|
||||
|
||||
@@ -9,8 +15,12 @@ uniform vec3 uPlayerEyePos;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 eyePos = ModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||
vec4 worldPos = vec4(vPosition, 1.0);
|
||||
#ifdef INSTANCED
|
||||
worldPos = mat4(iModel0, iModel1, iModel2, iModel3) * worldPos;
|
||||
#endif
|
||||
vec4 eyePos = ModelViewMatrix * worldPos;
|
||||
fogDistance = length(eyePos.xyz - uPlayerEyePos);
|
||||
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||
gl_Position = ProjectionModelViewMatrix * worldPos;
|
||||
texCoord = vTexCoord;
|
||||
}
|
||||
Loaded 100 of 568 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user